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", | ||||
|   "version": "0.1.0", | ||||
|   "private": true, | ||||
|   "scripts": { | ||||
|     "start": "react-scripts start", | ||||
|     "build": "react-scripts build", | ||||
|     "test": "react-scripts test", | ||||
|     "eject": "react-scripts eject" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@emotion/react": "^11.11.3", | ||||
|     "@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/material": "^5.15.20", | ||||
|     "@mui/styles": "^5.16.4", | ||||
| @ -17,23 +21,19 @@ | ||||
|     "@testing-library/react": "^13.4.0", | ||||
|     "@testing-library/user-event": "^13.5.0", | ||||
|     "axios": "^1.6.7", | ||||
|     "lucide-react": "^0.511.0", | ||||
|     "mdb-react-ui-kit": "^7.1.0", | ||||
|     "react": "^18.2.0", | ||||
|     "react-barcode": "^1.5.3", | ||||
|     "react-data-grid": "^7.0.0-beta.44", | ||||
|     "react-dom": "^18.2.0", | ||||
|     "react-google-recaptcha": "^3.1.0", | ||||
|     "react-icons": "^5.2.1", | ||||
|     "react-qr-code": "^2.0.14", | ||||
|     "react-router-dom": "^6.21.3", | ||||
|     "react-scripts": "^5.0.1", | ||||
|     "web-vitals": "^2.1.4" | ||||
|   }, | ||||
|   "scripts": { | ||||
|     "start": "react-scripts start", | ||||
|     "build": "react-scripts build", | ||||
|     "test": "react-scripts test", | ||||
|     "eject": "react-scripts eject" | ||||
|   }, | ||||
|   "eslintConfig": { | ||||
|     "extends": [ | ||||
|       "react-app", | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| // postcss.config.js
 | ||||
| module.exports = { | ||||
|     plugins: { | ||||
|       tailwindcss: {}, | ||||
|       autoprefixer: {}, | ||||
|     }, | ||||
|   }; | ||||
| // postcss.config.js
 | ||||
| module.exports = { | ||||
|     plugins: { | ||||
|       tailwindcss: {}, | ||||
|       autoprefixer: {}, | ||||
|     }, | ||||
|   }; | ||||
|    | ||||
| @ -46,3 +46,4 @@ | ||||
| /* .login-container input[type="checkbox"] { | ||||
|   margin-right: 5px; | ||||
| }   */ | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										48
									
								
								src/App.js
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								src/App.js
									
									
									
									
									
								
							| @ -1,7 +1,6 @@ | ||||
| 
 | ||||
| 
 | ||||
| import React from "react"; | ||||
| import { Routes, Route } from "react-router-dom"; | ||||
| import { BrowserRouter as Router } from 'react-router-dom'; | ||||
| import Login from "./components/Login/Login"; | ||||
| import Dashboard from "./components/Dashboard/dashboard"; | ||||
| import UserMaintance from "./components/Dashboard/UserMaintance"; | ||||
| @ -12,35 +11,28 @@ import DynamicTable from "./components/Dashboard/Dynamictable"; | ||||
| import Form from "./components/Dashboard/Form"; | ||||
| import ForgotPassword from "./components/Login/ForgotPassword"; | ||||
| import CreateAccount from "./components/Login/CreateAccount"; | ||||
| import Apitest from "./components/Dashboard/Test/Apitest"; | ||||
| import DashboardBuilder from "./components/Dashboard/DashboardBuilder"; | ||||
| 
 | ||||
| const App = () => { | ||||
|   return ( | ||||
|     <Routes> | ||||
|       <Route path="/" element={<Login />} /> | ||||
|       <Route path="/Dashboard" element={<Dashboard />} /> | ||||
|       <Route path="/UserGroupMaintance" element={<UserGroupMaintance />} /> | ||||
|       <Route path="/Dashboard/UserMaintance" element={<UserMaintance />} /> | ||||
|       <Route path="/CodeExtension" element={<CodeExtension />} /> | ||||
|       <Route | ||||
|         path="/Dashboard/DashboardBuilder" | ||||
|         element={<dashboardBuilder />} | ||||
|       /> | ||||
|       <Route path="/Extension" element={<Extension />} /> | ||||
|       <Route path="/Dynamictable" element={<DynamicTable />} /> | ||||
|       <Route path="/Form" element={<Form />} /> | ||||
|       <Route path="/ForgotPassword" element={<ForgotPassword />} /> | ||||
|       <Route path="/CreateAccount" element={<CreateAccount />} /> | ||||
|       <Route path="/Test" element={<Apitest />} /> | ||||
| 
 | ||||
|       {/* buildercomponents */} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     </Routes> | ||||
|     <div> | ||||
|       <Router> | ||||
|         <Routes> | ||||
|           <Route path="/" element={<Login />} /> | ||||
|           <Route path="/Dashboard" element={<Dashboard />} /> | ||||
|           <Route path="/UserGroupMaintance" element={<UserGroupMaintance />} /> | ||||
|           <Route path="/Dashboard/UserMaintance" element={<UserMaintance />} /> | ||||
|           <Route path="/CodeExtension" element={<CodeExtension />} /> | ||||
|           <Route path="/Dashboard/DashboardBuilder" element={<DashboardBuilder />} /> | ||||
|           <Route path="/Extension" element={<Extension />} /> | ||||
|           <Route path="/Dynamictable" element={<DynamicTable />} /> | ||||
|           <Route path="/Form" element={<Form />} /> | ||||
|           <Route path="/ForgotPassword" element={<ForgotPassword />} /> | ||||
|           <Route path="/CreateAccount" element={<CreateAccount />} /> | ||||
|         </Routes> | ||||
|       </Router> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default App; | ||||
| export default App; | ||||
|  | ||||
| @ -1,26 +1,26 @@ | ||||
| import React, { Component } from 'react'; | ||||
| 
 | ||||
| class ErrorBoundary extends Component { | ||||
|   constructor(props) { | ||||
|     super(props); | ||||
|     this.state = { hasError: false }; | ||||
|   } | ||||
| 
 | ||||
|   static getDerivedStateFromError(error) { | ||||
|     return { hasError: true }; | ||||
|   } | ||||
| 
 | ||||
|   componentDidCatch(error, errorInfo) { | ||||
|     console.error("Error Boundary Caught an Error", error, errorInfo); | ||||
|   } | ||||
| 
 | ||||
|   render() { | ||||
|     if (this.state.hasError) { | ||||
|       return <h1>Something went wrong.</h1>; | ||||
|     } | ||||
| 
 | ||||
|     return this.props.children;  | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export default ErrorBoundary; | ||||
| import React, { Component } from 'react'; | ||||
| 
 | ||||
| class ErrorBoundary extends Component { | ||||
|   constructor(props) { | ||||
|     super(props); | ||||
|     this.state = { hasError: false }; | ||||
|   } | ||||
| 
 | ||||
|   static getDerivedStateFromError(error) { | ||||
|     return { hasError: true }; | ||||
|   } | ||||
| 
 | ||||
|   componentDidCatch(error, errorInfo) { | ||||
|     console.error("Error Boundary Caught an Error", error, errorInfo); | ||||
|   } | ||||
| 
 | ||||
|   render() { | ||||
|     if (this.state.hasError) { | ||||
|       return <h1>Something went wrong.</h1>; | ||||
|     } | ||||
| 
 | ||||
|     return this.props.children;  | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 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 { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; | ||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||
| import { faEllipsisV } from "@fortawesome/free-solid-svg-icons"; | ||||
| 
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| function CustomToolbar({ apiRef, handleModal }) { | ||||
|   const handleGoToPage1 = () => { | ||||
|     if (apiRef.current) { | ||||
|       apiRef.current.setPage(1); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <GridToolbarContainer className="flex justify-between p-2 bg-gray-200"> | ||||
|       <Button | ||||
|         onClick={handleGoToPage1} | ||||
|         className="bg-blue-500 text-white px-4 py-2 rounded shadow hover:bg-blue-600" | ||||
|       > | ||||
|         Go to page 1 | ||||
|       </Button> | ||||
|       <Button | ||||
|         onClick={handleModal} | ||||
|         className="bg-green-500 text-white px-4 py-2 rounded shadow hover:bg-green-600" | ||||
|       > | ||||
|         Add item | ||||
|       </Button> | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function ApiRegistery() { | ||||
|   const [menuItems, setMenuItems] = useState([]); | ||||
|   const [selectedMenuItem, setSelectedMenuItem] = useState(null); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const apiRef = useRef(null); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("token"); // Get token from local storage
 | ||||
|       try { | ||||
|         const response = await fetch( | ||||
|           `${api}/Api_registery_header/Api_registery_header`, | ||||
|           { | ||||
|             headers: { | ||||
|               Authorization: `Bearer ${token}`, | ||||
|             }, | ||||
|           } | ||||
|         ); | ||||
|         const data = await response.json(); | ||||
|         setMenuItems(data); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (menuItemId) => { | ||||
|     setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { | ||||
|       field: "id", | ||||
|       headerName: "ID", | ||||
|       width: 300, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "table_name", | ||||
|       headerName: "Table Name", | ||||
|       width: 350, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "actions", | ||||
|       headerName: "Actions", | ||||
|       width: 150, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div className="relative"> | ||||
|           <div | ||||
|             className="cursor-pointer" | ||||
|             onClick={() => handleThreeDotsClick(row.id)} | ||||
|           > | ||||
|             <FontAwesomeIcon icon={faEllipsisV} /> | ||||
|           </div> | ||||
|           {selectedMenuItem === row.id && ( | ||||
|             <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"> | ||||
|                 Edit | ||||
|               </button> | ||||
|               <button className="block px-4 py-2 text-gray-800 hover:bg-gray-200 w-full text-left"> | ||||
|                 Delete | ||||
|               </button> | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ), | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="flex justify-center mt-5"> | ||||
|       <Box className="w-full max-w-7xl"> | ||||
|         <div className="bg-white p-4 rounded shadow-md"> | ||||
|           <h1 className="text-2xl font-bold mb-4 text-white bg-gray-400 p-3"> | ||||
|             API Registry | ||||
|           </h1> | ||||
|           <DataGrid | ||||
|             rows={menuItems} | ||||
|             columns={columns} | ||||
|             components={{ | ||||
|               Toolbar: () => ( | ||||
|                 <CustomToolbar | ||||
|                   apiRef={apiRef} | ||||
|                   handleModal={() => setIsModalOpen(true)} | ||||
|                 /> | ||||
|               ), | ||||
|             }} | ||||
|             pageSize={10} | ||||
|             onGridReady={(gridApi) => { | ||||
|               apiRef.current = gridApi; | ||||
|             }} | ||||
|           /> | ||||
|         </div> | ||||
|       </Box> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default ApiRegistery; | ||||
| 
 | ||||
| import React, { useState, useEffect, useRef } from "react"; | ||||
| import { Box, Button } from "@mui/material"; | ||||
| import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; | ||||
| import { BsThreeDotsVertical } from "react-icons/bs"; // Importing react-icons
 | ||||
| 
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| function CustomToolbar({ apiRef, handleModal }) { | ||||
|   const handleGoToPage1 = () => { | ||||
|     if (apiRef.current) { | ||||
|       apiRef.current.setPage(1); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <GridToolbarContainer className="flex justify-between p-2 bg-gray-200"> | ||||
|       <Button | ||||
|         onClick={handleGoToPage1} | ||||
|         className="bg-blue-500 text-white px-4 py-2 rounded shadow hover:bg-blue-600" | ||||
|       > | ||||
|         Go to page 1 | ||||
|       </Button> | ||||
|       <Button | ||||
|         onClick={handleModal} | ||||
|         className="bg-green-500 text-white px-4 py-2 rounded shadow hover:bg-green-600" | ||||
|       > | ||||
|         Add item | ||||
|       </Button> | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function ApiRegistery() { | ||||
|   const [menuItems, setMenuItems] = useState([]); | ||||
|   const [selectedMenuItem, setSelectedMenuItem] = useState(null); | ||||
|    // eslint-disable-next-line
 | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const apiRef = useRef(null); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("token"); // Get token from local storage
 | ||||
|       try { | ||||
|         const response = await fetch( | ||||
|           `${api}/Api_registery_header/Api_registery_header`, | ||||
|           { | ||||
|             headers: { | ||||
|               Authorization: `Bearer ${token}`, | ||||
|             }, | ||||
|           } | ||||
|         ); | ||||
|         const data = await response.json(); | ||||
|         setMenuItems(data); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (menuItemId) => { | ||||
|     setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { | ||||
|       field: "id", | ||||
|       headerName: "ID", | ||||
|       width: 300, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "table_name", | ||||
|       headerName: "Table Name", | ||||
|       width: 350, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "actions", | ||||
|       headerName: "Actions", | ||||
|       width: 150, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div className="relative"> | ||||
|           <div | ||||
|             className="cursor-pointer" | ||||
|             onClick={() => handleThreeDotsClick(row.id)} | ||||
|           > | ||||
|             <BsThreeDotsVertical /> {/* Using react-icons */} | ||||
|           </div> | ||||
|           {selectedMenuItem === row.id && ( | ||||
|             <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"> | ||||
|                 Edit | ||||
|               </button> | ||||
|               <button className="block px-4 py-2 text-gray-800 hover:bg-gray-200 w-full text-left"> | ||||
|                 Delete | ||||
|               </button> | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ), | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="flex justify-center mt-5"> | ||||
|       <Box className="w-full max-w-7xl"> | ||||
|         <div className="bg-white p-4 rounded shadow-md"> | ||||
|           <h1 className="text-2xl font-bold mb-4 text-white bg-gray-400 p-3"> | ||||
|             API Registry | ||||
|           </h1> | ||||
|           <DataGrid | ||||
|             rows={menuItems} | ||||
|             columns={columns} | ||||
|             components={{ | ||||
|               Toolbar: () => ( | ||||
|                 <CustomToolbar | ||||
|                   apiRef={apiRef} | ||||
|                   handleModal={() => setIsModalOpen(true)} | ||||
|                 /> | ||||
|               ), | ||||
|             }} | ||||
|             pageSize={10} | ||||
|             onGridReady={(gridApi) => { | ||||
|               apiRef.current = gridApi; | ||||
|             }} | ||||
|           /> | ||||
|         </div> | ||||
|       </Box> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default ApiRegistery; | ||||
|  | ||||
| @ -1,64 +1,64 @@ | ||||
| .modal-overlay { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     background-color: rgba(0, 0, 0, 0.5); | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|   } | ||||
|    | ||||
|   .modal { | ||||
|     background-color: #fff; | ||||
|     padding: 20px; | ||||
|     border-radius: 8px; | ||||
|   } | ||||
|    | ||||
|   .modal-content { | ||||
|     margin-top: 20px; | ||||
|   } | ||||
|    | ||||
|   .close { | ||||
|     position: absolute; | ||||
|     top: 10px; | ||||
|     right: 10px; | ||||
|     cursor: pointer; | ||||
|     font-size: 20px; | ||||
|   } | ||||
|    | ||||
|   .close:hover { | ||||
|     color: red; | ||||
|   } | ||||
|   .popup { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     background-color: rgba(0, 0, 0, 0.5); | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|   } | ||||
|    | ||||
|   .popup-content { | ||||
|     background-color: #fff; | ||||
|     padding: 20px; | ||||
|     border-radius: 8px; | ||||
|     width: 400px; /* Adjust width as needed */ | ||||
|   } | ||||
|    | ||||
|   .close { | ||||
|     position: absolute; | ||||
|     top: 10px; | ||||
|     right: 10px; | ||||
|     cursor: pointer; | ||||
|     font-size: 20px; | ||||
|   } | ||||
|    | ||||
|   .close:hover { | ||||
|     color: red; | ||||
|   } | ||||
| .modal-overlay { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     background-color: rgba(0, 0, 0, 0.5); | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|   } | ||||
|    | ||||
|   .modal { | ||||
|     background-color: #fff; | ||||
|     padding: 20px; | ||||
|     border-radius: 8px; | ||||
|   } | ||||
|    | ||||
|   .modal-content { | ||||
|     margin-top: 20px; | ||||
|   } | ||||
|    | ||||
|   .close { | ||||
|     position: absolute; | ||||
|     top: 10px; | ||||
|     right: 10px; | ||||
|     cursor: pointer; | ||||
|     font-size: 20px; | ||||
|   } | ||||
|    | ||||
|   .close:hover { | ||||
|     color: red; | ||||
|   } | ||||
|   .popup { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     background-color: rgba(0, 0, 0, 0.5); | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|   } | ||||
|    | ||||
|   .popup-content { | ||||
|     background-color: #fff; | ||||
|     padding: 20px; | ||||
|     border-radius: 8px; | ||||
|     width: 400px; /* Adjust width as needed */ | ||||
|   } | ||||
|    | ||||
|   .close { | ||||
|     position: absolute; | ||||
|     top: 10px; | ||||
|     right: 10px; | ||||
|     cursor: pointer; | ||||
|     font-size: 20px; | ||||
|   } | ||||
|    | ||||
|   .close:hover { | ||||
|     color: red; | ||||
|   } | ||||
|    | ||||
| @ -1,302 +1,301 @@ | ||||
| import React, { useState, useEffect, useRef } from "react"; | ||||
| import { | ||||
|   Box, | ||||
|   Button, | ||||
|   Modal, | ||||
|   TextField, | ||||
|   Typography, | ||||
|   FormControl, | ||||
|   FormControlLabel, | ||||
|   Checkbox, | ||||
|   Radio, | ||||
|   RadioGroup, | ||||
|   Autocomplete, | ||||
| } from "@mui/material"; | ||||
| import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; | ||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||
| import { faEllipsisV } from "@fortawesome/free-solid-svg-icons"; | ||||
| import AirplanemodeActiveIcon from "@mui/icons-material/AirplanemodeActive"; | ||||
| import { Link } from "react-router-dom"; | ||||
| import Extension from "./Extension"; | ||||
| 
 | ||||
| function CustomToolbar({ handleModal }) { | ||||
|   return ( | ||||
|     <GridToolbarContainer className="flex justify-between p-2 bg-gray-200"> | ||||
|       <Button | ||||
|         className="bg-blue-500 text-white px-4 py-2 rounded shadow hover:bg-blue-600" | ||||
|         onClick={handleModal} | ||||
|       > | ||||
|         + | ||||
|       </Button> | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function CodeExtension() { | ||||
|   const [menuItems, setMenuItems] = useState([]); | ||||
|   const [selectedMenuItem, setSelectedMenuItem] = useState(null); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const [formData, setFormData] = useState({ | ||||
|     name: "", | ||||
|     email: "", | ||||
|     testing: "", | ||||
|     dataType: "", | ||||
|   }); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("token"); // Get token from local storage
 | ||||
|       try { | ||||
|         const response = await fetch(`${process.env.REACT_APP_API_BASE_URL}/api/extension`, { | ||||
|           headers: { | ||||
|             Authorization: `Bearer ${token}`, | ||||
|           }, | ||||
|         }); | ||||
|         const data = await response.json(); | ||||
|         setMenuItems(data); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (menuItemId) => { | ||||
|     setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); | ||||
|   }; | ||||
| 
 | ||||
|   const handleModalOpen = () => { | ||||
|     setIsModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   const handleModalClose = () => { | ||||
|     setIsModalOpen(false); | ||||
|     setFormData({ | ||||
|       name: "", | ||||
|       email: "", | ||||
|       testing: "", | ||||
|       dataType: "", | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleChange = (e) => { | ||||
|     const { name, value } = e.target; | ||||
|     setFormData({ ...formData, [name]: value }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleFormSubmit = (submittedDataType) => { | ||||
|     setFormData({ ...formData, dataType: submittedDataType }); | ||||
|     handleModalOpen(); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { field: "goto", headerName: "Goto", width: 200 }, | ||||
|     { field: "field_name", headerName: "Field Name", width: 250 }, | ||||
|     { field: "mapping", headerName: "Mapping", width: 200 }, | ||||
|     { field: "data_type", headerName: "Data Type", width: 200 }, | ||||
|     { | ||||
|       field: "actions", | ||||
|       headerName: "Actions", | ||||
|       width: 150, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div className="relative"> | ||||
|           <div | ||||
|             className="cursor-pointer" | ||||
|             onClick={() => handleThreeDotsClick(row.id)} | ||||
|           > | ||||
|             <FontAwesomeIcon icon={faEllipsisV} /> | ||||
|           </div> | ||||
|           {selectedMenuItem === row.id && ( | ||||
|             <div className="absolute right-0 mt-2 py-2 w-48 bg-white rounded-lg shadow-xl"> | ||||
|               {/* Implement your actions buttons here */} | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ), | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   const renderInputField = () => { | ||||
|     switch (formData.dataType) { | ||||
|       case "date": | ||||
|         return ( | ||||
|           <TextField | ||||
|             label="Date" | ||||
|             name="date" | ||||
|             type="date" | ||||
|             value={formData.date} | ||||
|             onChange={handleChange} | ||||
|             fullWidth | ||||
|             className="mt-2" | ||||
|           /> | ||||
|         ); | ||||
|       case "textfield": | ||||
|         return ( | ||||
|           <TextField | ||||
|             label="Text Field" | ||||
|             name="textfield" | ||||
|             value={formData.textfield} | ||||
|             onChange={handleChange} | ||||
|             fullWidth | ||||
|             className="mt-2" | ||||
|           /> | ||||
|         ); | ||||
|       case "longtext": | ||||
|         return ( | ||||
|           <TextField | ||||
|             label="Long Text" | ||||
|             name="longtext" | ||||
|             value={formData.longtext} | ||||
|             onChange={handleChange} | ||||
|             multiline | ||||
|             rows={4} | ||||
|             fullWidth | ||||
|             className="mt-2" | ||||
|           /> | ||||
|         ); | ||||
|       case "checkbox": | ||||
|         return ( | ||||
|           <FormControlLabel | ||||
|             className="mt-2" | ||||
|             control={ | ||||
|               <Checkbox | ||||
|                 checked={formData.checkbox || false} | ||||
|                 onChange={(e) => | ||||
|                   setFormData({ ...formData, checkbox: e.target.checked }) | ||||
|                 } | ||||
|               /> | ||||
|             } | ||||
|             label="Checkbox" | ||||
|           /> | ||||
|         ); | ||||
|       case "radiobutton": | ||||
|         return ( | ||||
|           <FormControl component="fieldset" className="mt-2"> | ||||
|             <RadioGroup | ||||
|               name="radiobutton" | ||||
|               value={formData.radiobutton || ""} | ||||
|               onChange={(e) => | ||||
|                 setFormData({ ...formData, radiobutton: e.target.value }) | ||||
|               } | ||||
|             > | ||||
|               <FormControlLabel | ||||
|                 value="option1" | ||||
|                 control={<Radio />} | ||||
|                 label="Option 1" | ||||
|               /> | ||||
|               <FormControlLabel | ||||
|                 value="option2" | ||||
|                 control={<Radio />} | ||||
|                 label="Option 2" | ||||
|               /> | ||||
|             </RadioGroup> | ||||
|           </FormControl> | ||||
|         ); | ||||
|       case "autocomplete": | ||||
|         return ( | ||||
|           <Autocomplete | ||||
|             options={["Option 1", "Option 2", "Option 3"]} | ||||
|             renderInput={(params) => ( | ||||
|               <TextField {...params} label="Autocomplete" /> | ||||
|             )} | ||||
|             value={formData.autocomplete || ""} | ||||
|             onChange={(e, newValue) => | ||||
|               setFormData({ ...formData, autocomplete: newValue }) | ||||
|             } | ||||
|             fullWidth | ||||
|             className="mt-2" | ||||
|           /> | ||||
|         ); | ||||
|       default: | ||||
|         return null; | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       <Box className="fixed top-0 left-0 w-full z-10 bg-white shadow"> | ||||
|         {/* Your header content here */} | ||||
|       </Box> | ||||
|       <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"> | ||||
|           <Typography | ||||
|             variant="h4" | ||||
|             className="text-center mb-4 text-3xl text-white bg-gray-400 p-3" | ||||
|           > | ||||
|             Token Registry | ||||
|           </Typography> | ||||
|           <div className="bg-gray-50 p-2 rounded shadow-inner"> | ||||
|             <DataGrid | ||||
|               rows={menuItems} | ||||
|               columns={columns} | ||||
|               pageSize={10} | ||||
|               components={{ | ||||
|                 Toolbar: () => <CustomToolbar handleModal={handleModalOpen} />, | ||||
|               }} | ||||
|               className="data-grid" | ||||
|             /> | ||||
|           </div> | ||||
|           <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"> | ||||
|               <Extension onSubmit={handleFormSubmit} /> | ||||
|               <Typography variant="h5" className="flex items-center mb-4"> | ||||
|                 <Link to="/Extension"> | ||||
|                   <AirplanemodeActiveIcon className="mr-2" /> | ||||
|                 </Link> | ||||
|                 Add Item | ||||
|               </Typography> | ||||
|               <form | ||||
|                 onSubmit={(e) => { | ||||
|                   e.preventDefault(); | ||||
|                   handleFormSubmit(formData.dataType); | ||||
|                 }} | ||||
|               > | ||||
|                 <div className="mb-2"> | ||||
|                   <TextField | ||||
|                     label="Name" | ||||
|                     name="name" | ||||
|                     value={formData.name} | ||||
|                     onChange={handleChange} | ||||
|                     fullWidth | ||||
|                   /> | ||||
|                 </div> | ||||
|                 <div className="mb-2"> | ||||
|                   <TextField | ||||
|                     label="Email" | ||||
|                     name="email" | ||||
|                     value={formData.email} | ||||
|                     onChange={handleChange} | ||||
|                     fullWidth | ||||
|                   /> | ||||
|                 </div> | ||||
|                 <div className="mb-2"> | ||||
|                   <TextField | ||||
|                     label="Testing" | ||||
|                     name="testing" | ||||
|                     value={formData.testing} | ||||
|                     onChange={handleChange} | ||||
|                     fullWidth | ||||
|                   /> | ||||
|                 </div> | ||||
|                 {renderInputField()} | ||||
|                 <div className="mt-4"> | ||||
|                   <Button | ||||
|                     type="submit" | ||||
|                     variant="contained" | ||||
|                     color="primary" | ||||
|                     fullWidth | ||||
|                   > | ||||
|                     Submit | ||||
|                   </Button> | ||||
|                 </div> | ||||
|               </form> | ||||
|             </Box> | ||||
|           </Modal> | ||||
|         </Box> | ||||
|       </Box> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default CodeExtension; | ||||
| import React, { useState, useEffect } from "react"; | ||||
| import { | ||||
|   Box, | ||||
|   Button, | ||||
|   Modal, | ||||
|   TextField, | ||||
|   Typography, | ||||
|   FormControl, | ||||
|   FormControlLabel, | ||||
|   Checkbox, | ||||
|   Radio, | ||||
|   RadioGroup, | ||||
|   Autocomplete, | ||||
| } from "@mui/material"; | ||||
| import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; | ||||
| import { FaEllipsisV } from "react-icons/fa"; // Importing react-icons instead of Font Awesome
 | ||||
| import AirplanemodeActiveIcon from "@mui/icons-material/AirplanemodeActive"; | ||||
| import { Link } from "react-router-dom"; | ||||
| import Extension from "./Extension"; | ||||
| 
 | ||||
| function CustomToolbar({ handleModal }) { | ||||
|   return ( | ||||
|     <GridToolbarContainer className="flex justify-between p-2 bg-gray-200"> | ||||
|       <Button | ||||
|         className="bg-blue-500 text-white px-4 py-2 rounded shadow hover:bg-blue-600" | ||||
|         onClick={handleModal} | ||||
|       > | ||||
|         + | ||||
|       </Button> | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function CodeExtension() { | ||||
|   const [menuItems, setMenuItems] = useState([]); | ||||
|   const [selectedMenuItem, setSelectedMenuItem] = useState(null); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const [formData, setFormData] = useState({ | ||||
|     name: "", | ||||
|     email: "", | ||||
|     testing: "", | ||||
|     dataType: "", | ||||
|   }); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("authToken"); // Get token from local storage
 | ||||
|       try { | ||||
|         const response = await fetch(`${process.env.REACT_APP_API_BASE_URL}/api/extension`, { | ||||
|           headers: { | ||||
|             Authorization: `Bearer ${token}`, | ||||
|           }, | ||||
|         }); | ||||
|         const data = await response.json(); | ||||
|         setMenuItems(data); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (menuItemId) => { | ||||
|     setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); | ||||
|   }; | ||||
| 
 | ||||
|   const handleModalOpen = () => { | ||||
|     setIsModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   const handleModalClose = () => { | ||||
|     setIsModalOpen(false); | ||||
|     setFormData({ | ||||
|       name: "", | ||||
|       email: "", | ||||
|       testing: "", | ||||
|       dataType: "", | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleChange = (e) => { | ||||
|     const { name, value } = e.target; | ||||
|     setFormData({ ...formData, [name]: value }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleFormSubmit = (submittedDataType) => { | ||||
|     setFormData({ ...formData, dataType: submittedDataType }); | ||||
|     handleModalOpen(); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { field: "goto", headerName: "Goto", width: 200 }, | ||||
|     { field: "field_name", headerName: "Field Name", width: 250 }, | ||||
|     { field: "mapping", headerName: "Mapping", width: 200 }, | ||||
|     { field: "data_type", headerName: "Data Type", width: 200 }, | ||||
|     { | ||||
|       field: "actions", | ||||
|       headerName: "Actions", | ||||
|       width: 150, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div className="relative"> | ||||
|           <div | ||||
|             className="cursor-pointer" | ||||
|             onClick={() => handleThreeDotsClick(row.id)} | ||||
|           > | ||||
|             <FaEllipsisV /> {/* Using react-icons instead of Font Awesome */} | ||||
|           </div> | ||||
|           {selectedMenuItem === row.id && ( | ||||
|             <div className="absolute right-0 mt-2 py-2 w-48 bg-white rounded-lg shadow-xl"> | ||||
|               {/* Implement your actions buttons here */} | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ), | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   const renderInputField = () => { | ||||
|     switch (formData.dataType) { | ||||
|       case "date": | ||||
|         return ( | ||||
|           <TextField | ||||
|             label="Date" | ||||
|             name="date" | ||||
|             type="date" | ||||
|             value={formData.date} | ||||
|             onChange={handleChange} | ||||
|             fullWidth | ||||
|             className="mt-2" | ||||
|           /> | ||||
|         ); | ||||
|       case "textfield": | ||||
|         return ( | ||||
|           <TextField | ||||
|             label="Text Field" | ||||
|             name="textfield" | ||||
|             value={formData.textfield} | ||||
|             onChange={handleChange} | ||||
|             fullWidth | ||||
|             className="mt-2" | ||||
|           /> | ||||
|         ); | ||||
|       case "longtext": | ||||
|         return ( | ||||
|           <TextField | ||||
|             label="Long Text" | ||||
|             name="longtext" | ||||
|             value={formData.longtext} | ||||
|             onChange={handleChange} | ||||
|             multiline | ||||
|             rows={4} | ||||
|             fullWidth | ||||
|             className="mt-2" | ||||
|           /> | ||||
|         ); | ||||
|       case "checkbox": | ||||
|         return ( | ||||
|           <FormControlLabel | ||||
|             className="mt-2" | ||||
|             control={ | ||||
|               <Checkbox | ||||
|                 checked={formData.checkbox || false} | ||||
|                 onChange={(e) => | ||||
|                   setFormData({ ...formData, checkbox: e.target.checked }) | ||||
|                 } | ||||
|               /> | ||||
|             } | ||||
|             label="Checkbox" | ||||
|           /> | ||||
|         ); | ||||
|       case "radiobutton": | ||||
|         return ( | ||||
|           <FormControl component="fieldset" className="mt-2"> | ||||
|             <RadioGroup | ||||
|               name="radiobutton" | ||||
|               value={formData.radiobutton || ""} | ||||
|               onChange={(e) => | ||||
|                 setFormData({ ...formData, radiobutton: e.target.value }) | ||||
|               } | ||||
|             > | ||||
|               <FormControlLabel | ||||
|                 value="option1" | ||||
|                 control={<Radio />} | ||||
|                 label="Option 1" | ||||
|               /> | ||||
|               <FormControlLabel | ||||
|                 value="option2" | ||||
|                 control={<Radio />} | ||||
|                 label="Option 2" | ||||
|               /> | ||||
|             </RadioGroup> | ||||
|           </FormControl> | ||||
|         ); | ||||
|       case "autocomplete": | ||||
|         return ( | ||||
|           <Autocomplete | ||||
|             options={["Option 1", "Option 2", "Option 3"]} | ||||
|             renderInput={(params) => ( | ||||
|               <TextField {...params} label="Autocomplete" /> | ||||
|             )} | ||||
|             value={formData.autocomplete || ""} | ||||
|             onChange={(e, newValue) => | ||||
|               setFormData({ ...formData, autocomplete: newValue }) | ||||
|             } | ||||
|             fullWidth | ||||
|             className="mt-2" | ||||
|           /> | ||||
|         ); | ||||
|       default: | ||||
|         return null; | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       <Box className="fixed top-0 left-0 w-full z-10 bg-white shadow"> | ||||
|         {/* Your header content here */} | ||||
|       </Box> | ||||
|       <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"> | ||||
|           <Typography | ||||
|             variant="h4" | ||||
|             className="text-center mb-4 text-3xl text-white bg-gray-400 p-3" | ||||
|           > | ||||
|             Token Registry | ||||
|           </Typography> | ||||
|           <div className="bg-gray-50 p-2 rounded shadow-inner"> | ||||
|             <DataGrid | ||||
|               rows={menuItems} | ||||
|               columns={columns} | ||||
|               pageSize={10} | ||||
|               components={{ | ||||
|                 Toolbar: () => <CustomToolbar handleModal={handleModalOpen} />, | ||||
|               }} | ||||
|               className="data-grid" | ||||
|             /> | ||||
|           </div> | ||||
|           <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"> | ||||
|               <Extension onSubmit={handleFormSubmit} /> | ||||
|               <Typography variant="h5" className="flex items-center mb-4"> | ||||
|                 <Link to="/Extension"> | ||||
|                   <AirplanemodeActiveIcon className="mr-2" /> | ||||
|                 </Link> | ||||
|                 Add Item | ||||
|               </Typography> | ||||
|               <form | ||||
|                 onSubmit={(e) => { | ||||
|                   e.preventDefault(); | ||||
|                   handleFormSubmit(formData.dataType); | ||||
|                 }} | ||||
|               > | ||||
|                 <div className="mb-2"> | ||||
|                   <TextField | ||||
|                     label="Name" | ||||
|                     name="name" | ||||
|                     value={formData.name} | ||||
|                     onChange={handleChange} | ||||
|                     fullWidth | ||||
|                   /> | ||||
|                 </div> | ||||
|                 <div className="mb-2"> | ||||
|                   <TextField | ||||
|                     label="Email" | ||||
|                     name="email" | ||||
|                     value={formData.email} | ||||
|                     onChange={handleChange} | ||||
|                     fullWidth | ||||
|                   /> | ||||
|                 </div> | ||||
|                 <div className="mb-2"> | ||||
|                   <TextField | ||||
|                     label="Testing" | ||||
|                     name="testing" | ||||
|                     value={formData.testing} | ||||
|                     onChange={handleChange} | ||||
|                     fullWidth | ||||
|                   /> | ||||
|                 </div> | ||||
|                 {renderInputField()} | ||||
|                 <div className="mt-4"> | ||||
|                   <Button | ||||
|                     type="submit" | ||||
|                     variant="contained" | ||||
|                     color="primary" | ||||
|                     fullWidth | ||||
|                   > | ||||
|                     Submit | ||||
|                   </Button> | ||||
|                 </div> | ||||
|               </form> | ||||
|             </Box> | ||||
|           </Modal> | ||||
|         </Box> | ||||
|       </Box> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default CodeExtension; | ||||
|  | ||||
| @ -1,161 +1,161 @@ | ||||
| import React, { useState, useEffect } from "react"; | ||||
| import axios from "axios"; | ||||
| import { useLocation, useNavigate } from "react-router-dom"; | ||||
| import { | ||||
|   Button, | ||||
|   IconButton, | ||||
|   Table, | ||||
|   TableBody, | ||||
|   TableCell, | ||||
|   TableContainer, | ||||
|   TableHead, | ||||
|   TableRow, | ||||
|   Paper, | ||||
|   Typography, | ||||
|   Box, | ||||
| } from "@mui/material"; | ||||
| import DeleteIcon from "@mui/icons-material/Delete"; | ||||
| import BuildIcon from "@mui/icons-material/Build"; | ||||
| import AddIcon from "@mui/icons-material/Add"; | ||||
| 
 | ||||
| // Define the API base URL using the environment variable
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| const DynamicTable = () => { | ||||
|   const [forms, setForms] = useState([]); | ||||
|   const location = useLocation(); | ||||
|   const navigate = useNavigate(); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (location.state && location.state.formData) { | ||||
|       setForms((prevForms) => [...prevForms, location.state.formData]); | ||||
|     } else { | ||||
|       fetchForms(); | ||||
|     } | ||||
|   }, [location.state]); | ||||
| 
 | ||||
|   const fetchForms = async () => { | ||||
|     const token = localStorage.getItem("token"); // Get token from local storage
 | ||||
|     try { | ||||
|       const response = await axios.get(`${api}/api/form_setup`, { | ||||
|         headers: { | ||||
|           Authorization: `Bearer ${token}`, | ||||
|         }, | ||||
|       }); | ||||
|       if (Array.isArray(response.data)) { | ||||
|         setForms(response.data); | ||||
|       } else { | ||||
|         console.error("Unexpected response format:", response.data); | ||||
|         setForms([]); | ||||
|       } | ||||
|     } catch (error) { | ||||
|       console.error("Error fetching data:", error); | ||||
|       setForms([]); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleDelete = async (id) => { | ||||
|     const token = localStorage.getItem("token"); // Get token from local storage
 | ||||
|     try { | ||||
|       await axios.delete(`${api}/api/form_setup/${id}`, { | ||||
|         headers: { | ||||
|           Authorization: `Bearer ${token}`, | ||||
|         }, | ||||
|       }); | ||||
|       fetchForms(); | ||||
|     } catch (error) { | ||||
|       console.error("Error deleting form:", error); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleBuild = async (id) => { | ||||
|     const token = localStorage.getItem("token"); // Get token from local storage
 | ||||
|     try { | ||||
|       await axios.post( | ||||
|         `${api}/api/dynamic_form_build`, | ||||
|         { id }, | ||||
|         { | ||||
|           headers: { | ||||
|             Authorization: `Bearer ${token}`, | ||||
|           }, | ||||
|         } | ||||
|       ); | ||||
|     } catch (error) { | ||||
|       console.error("Error building form:", error); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleAdd = () => { | ||||
|     navigate("/form"); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <Box className="p-5 bg-gray-100 min-h-screen"> | ||||
|       <Typography | ||||
|         variant="h4" | ||||
|         gutterBottom | ||||
|         className="text-center text-white bg-gray-700 text-3xl p-3 mb-5 rounded" | ||||
|       > | ||||
|         Dynamic Form | ||||
|       </Typography> | ||||
|       <Button | ||||
|         variant="contained" | ||||
|         color="primary" | ||||
|         startIcon={<AddIcon />} | ||||
|         onClick={handleAdd} | ||||
|         className="mb-5 bg-blue-500 hover:bg-blue-600" | ||||
|       > | ||||
|         Add | ||||
|       </Button> | ||||
|       <TableContainer component={Paper} className="overflow-x-auto"> | ||||
|         <Table> | ||||
|           <TableHead className="bg-gray-300 text-black"> | ||||
|             <TableRow> | ||||
|               <TableCell>Go To</TableCell> | ||||
|               <TableCell>Form Name</TableCell> | ||||
|               <TableCell>Form Description</TableCell> | ||||
|               <TableCell>Related To</TableCell> | ||||
|               <TableCell>Page Event</TableCell> | ||||
|               <TableCell>Button Caption</TableCell> | ||||
|               <TableCell>Go To Form</TableCell> | ||||
|               <TableCell>Action</TableCell> | ||||
|             </TableRow> | ||||
|           </TableHead> | ||||
|           <TableBody> | ||||
|             {forms.map((form, index) => ( | ||||
|               <TableRow key={index}> | ||||
|                 <TableCell> | ||||
|                   <Button | ||||
|                     variant="outlined" | ||||
|                     startIcon={<BuildIcon />} | ||||
|                     onClick={() => handleBuild(form.id)} | ||||
|                     className="border-blue-500 text-blue-500 hover:bg-blue-100" | ||||
|                   > | ||||
|                     Build | ||||
|                   </Button> | ||||
|                 </TableCell> | ||||
|                 <TableCell>{form.formName}</TableCell> | ||||
|                 <TableCell>{form.formDescription}</TableCell> | ||||
|                 <TableCell>{form.relatedTo}</TableCell> | ||||
|                 <TableCell>{form.pageEvent}</TableCell> | ||||
|                 <TableCell>{form.buttonCaption}</TableCell> | ||||
|                 <TableCell>{form.goToForm}</TableCell> | ||||
|                 <TableCell> | ||||
|                   <IconButton | ||||
|                     color="secondary" | ||||
|                     onClick={() => handleDelete(form.id)} | ||||
|                     className="text-red-500 hover:text-red-700" | ||||
|                   > | ||||
|                     <DeleteIcon /> | ||||
|                   </IconButton> | ||||
|                 </TableCell> | ||||
|               </TableRow> | ||||
|             ))} | ||||
|           </TableBody> | ||||
|         </Table> | ||||
|       </TableContainer> | ||||
|     </Box> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default DynamicTable; | ||||
| import React, { useState, useEffect } from "react"; | ||||
| import axios from "axios"; | ||||
| import { useLocation, useNavigate } from "react-router-dom"; | ||||
| import { | ||||
|   Button, | ||||
|   IconButton, | ||||
|   Table, | ||||
|   TableBody, | ||||
|   TableCell, | ||||
|   TableContainer, | ||||
|   TableHead, | ||||
|   TableRow, | ||||
|   Paper, | ||||
|   Typography, | ||||
|   Box, | ||||
| } from "@mui/material"; | ||||
| import DeleteIcon from "@mui/icons-material/Delete"; | ||||
| import BuildIcon from "@mui/icons-material/Build"; | ||||
| import AddIcon from "@mui/icons-material/Add"; | ||||
| 
 | ||||
| // Define the API base URL using the environment variable
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| const DynamicTable = () => { | ||||
|   const [forms, setForms] = useState([]); | ||||
|   const location = useLocation(); | ||||
|   const navigate = useNavigate(); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (location.state && location.state.formData) { | ||||
|       setForms((prevForms) => [...prevForms, location.state.formData]); | ||||
|     } else { | ||||
|       fetchForms(); | ||||
|     } | ||||
|   }, [location.state]); | ||||
| 
 | ||||
|   const fetchForms = async () => { | ||||
|     const token = localStorage.getItem("authToken"); // Get token from local storage
 | ||||
|     try { | ||||
|       const response = await axios.get(`${api}/api/form_setup`, { | ||||
|         headers: { | ||||
|           Authorization: `Bearer ${token}`, | ||||
|         }, | ||||
|       }); | ||||
|       if (Array.isArray(response.data)) { | ||||
|         setForms(response.data); | ||||
|       } else { | ||||
|         console.error("Unexpected response format:", response.data); | ||||
|         setForms([]); | ||||
|       } | ||||
|     } catch (error) { | ||||
|       console.error("Error fetching data:", error); | ||||
|       setForms([]); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleDelete = async (id) => { | ||||
|     const token = localStorage.getItem("authToken"); // Get token from local storage
 | ||||
|     try { | ||||
|       await axios.delete(`${api}/api/form_setup/${id}`, { | ||||
|         headers: { | ||||
|           Authorization: `Bearer ${token}`, | ||||
|         }, | ||||
|       }); | ||||
|       fetchForms(); | ||||
|     } catch (error) { | ||||
|       console.error("Error deleting form:", error); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleBuild = async (id) => { | ||||
|     const token = localStorage.getItem("authToken"); // Get token from local storage
 | ||||
|     try { | ||||
|       await axios.post( | ||||
|         `${api}/api/dynamic_form_build`, | ||||
|         { id }, | ||||
|         { | ||||
|           headers: { | ||||
|             Authorization: `Bearer ${token}`, | ||||
|           }, | ||||
|         } | ||||
|       ); | ||||
|     } catch (error) { | ||||
|       console.error("Error building form:", error); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleAdd = () => { | ||||
|     navigate("/form"); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <Box className="p-5 bg-gray-100 min-h-screen"> | ||||
|       <Typography | ||||
|         variant="h4" | ||||
|         gutterBottom | ||||
|         className="text-center text-white bg-gray-700 text-3xl p-3 mb-5 rounded" | ||||
|       > | ||||
|         Dynamic Form | ||||
|       </Typography> | ||||
|       <Button | ||||
|         variant="contained" | ||||
|         color="primary" | ||||
|         startIcon={<AddIcon />} | ||||
|         onClick={handleAdd} | ||||
|         className="mb-5 bg-blue-500 hover:bg-blue-600" | ||||
|       > | ||||
|         Add | ||||
|       </Button> | ||||
|       <TableContainer component={Paper} className="overflow-x-auto"> | ||||
|         <Table> | ||||
|           <TableHead className="bg-gray-300 text-black"> | ||||
|             <TableRow> | ||||
|               <TableCell>Go To</TableCell> | ||||
|               <TableCell>Form Name</TableCell> | ||||
|               <TableCell>Form Description</TableCell> | ||||
|               <TableCell>Related To</TableCell> | ||||
|               <TableCell>Page Event</TableCell> | ||||
|               <TableCell>Button Caption</TableCell> | ||||
|               <TableCell>Go To Form</TableCell> | ||||
|               <TableCell>Action</TableCell> | ||||
|             </TableRow> | ||||
|           </TableHead> | ||||
|           <TableBody> | ||||
|             {forms.map((form, index) => ( | ||||
|               <TableRow key={index}> | ||||
|                 <TableCell> | ||||
|                   <Button | ||||
|                     variant="outlined" | ||||
|                     startIcon={<BuildIcon />} | ||||
|                     onClick={() => handleBuild(form.id)} | ||||
|                     className="border-blue-500 text-blue-500 hover:bg-blue-100" | ||||
|                   > | ||||
|                     Build | ||||
|                   </Button> | ||||
|                 </TableCell> | ||||
|                 <TableCell>{form.formName}</TableCell> | ||||
|                 <TableCell>{form.formDescription}</TableCell> | ||||
|                 <TableCell>{form.relatedTo}</TableCell> | ||||
|                 <TableCell>{form.pageEvent}</TableCell> | ||||
|                 <TableCell>{form.buttonCaption}</TableCell> | ||||
|                 <TableCell>{form.goToForm}</TableCell> | ||||
|                 <TableCell> | ||||
|                   <IconButton | ||||
|                     color="secondary" | ||||
|                     onClick={() => handleDelete(form.id)} | ||||
|                     className="text-red-500 hover:text-red-700" | ||||
|                   > | ||||
|                     <DeleteIcon /> | ||||
|                   </IconButton> | ||||
|                 </TableCell> | ||||
|               </TableRow> | ||||
|             ))} | ||||
|           </TableBody> | ||||
|         </Table> | ||||
|       </TableContainer> | ||||
|     </Box> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default DynamicTable; | ||||
|  | ||||
| @ -1,93 +1,93 @@ | ||||
| import React, { useState } from 'react'; | ||||
| import { TextField, Button, Typography, Select, MenuItem } from '@mui/material'; | ||||
| import { useNavigate } from 'react-router-dom'; | ||||
| 
 | ||||
| const Extension = ({ onSubmit }) => { | ||||
|   const [formData, setFormData] = useState({ | ||||
|     type: '', | ||||
|     fieldName: '', | ||||
|     mapping: '', | ||||
|     dataType: '' | ||||
|   }); | ||||
| 
 | ||||
|   const navigate = useNavigate(); | ||||
| 
 | ||||
|   const handleChange = (e) => { | ||||
|     const { name, value } = e.target; | ||||
|     setFormData({ ...formData, [name]: value }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSubmit = (e) => { | ||||
|     e.preventDefault(); | ||||
|     if (typeof onSubmit === 'function') { | ||||
|       onSubmit(formData.dataType); | ||||
|     } | ||||
|     // Navigate to CodeExtension page with the form data
 | ||||
|     navigate('/Codeextension', { state: { formData } }); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div style={{ maxWidth: '600px', margin: '0 auto' }}> | ||||
|       <Typography variant="h4" gutterBottom>Add Item</Typography> | ||||
|       <form onSubmit={handleSubmit}> | ||||
|         <div> | ||||
|           <Select | ||||
|             label="Type" | ||||
|             name="type" | ||||
|             value={formData.type} | ||||
|             onChange={handleChange} | ||||
|             fullWidth | ||||
|             required | ||||
|           > | ||||
|             <MenuItem value="Header">Header</MenuItem> | ||||
|             <MenuItem value="Line">Line</MenuItem> | ||||
|           </Select> | ||||
|         </div> | ||||
|         <div> | ||||
|           <TextField | ||||
|             label="Field Name" | ||||
|             name="fieldName" | ||||
|             value={formData.fieldName} | ||||
|             onChange={handleChange} | ||||
|             fullWidth | ||||
|             required | ||||
|           /> | ||||
|         </div> | ||||
|         <div> | ||||
|           <Select | ||||
|             label="Mapping" | ||||
|             name="mapping" | ||||
|             value={formData.mapping} | ||||
|             onChange={handleChange} | ||||
|             fullWidth | ||||
|             required | ||||
|           > | ||||
|             {[...Array(15).keys()].map(num => ( | ||||
|               <MenuItem key={num + 1} value={`EXTN${num + 1}`}>{`EXTN${num + 1}`}</MenuItem> | ||||
|             ))} | ||||
|           </Select> | ||||
|         </div> | ||||
|         <div> | ||||
|           <Select | ||||
|             label="Data Type" | ||||
|             name="dataType" | ||||
|             value={formData.dataType} | ||||
|             onChange={handleChange} | ||||
|             fullWidth | ||||
|             required | ||||
|           > | ||||
|             <MenuItem value="textfield">Textfield</MenuItem> | ||||
|             <MenuItem value="longtext">Longtext</MenuItem> | ||||
|             <MenuItem value="date">Date</MenuItem> | ||||
|             <MenuItem value="checkbox">Checkbox</MenuItem> | ||||
|             <MenuItem value="radiobutton">Radiobutton</MenuItem> | ||||
|             <MenuItem value="autocomplete">Autocomplete</MenuItem> | ||||
|           </Select> | ||||
|         </div> | ||||
|         <Button type="submit" variant="contained" sx={{ mt: 2 }}>Submit</Button> | ||||
|       </form> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default Extension; | ||||
| import React, { useState } from 'react'; | ||||
| import { TextField, Button, Typography, Select, MenuItem } from '@mui/material'; | ||||
| import { useNavigate } from 'react-router-dom'; | ||||
| 
 | ||||
| const Extension = ({ onSubmit }) => { | ||||
|   const [formData, setFormData] = useState({ | ||||
|     type: '', | ||||
|     fieldName: '', | ||||
|     mapping: '', | ||||
|     dataType: '' | ||||
|   }); | ||||
| 
 | ||||
|   const navigate = useNavigate(); | ||||
| 
 | ||||
|   const handleChange = (e) => { | ||||
|     const { name, value } = e.target; | ||||
|     setFormData({ ...formData, [name]: value }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSubmit = (e) => { | ||||
|     e.preventDefault(); | ||||
|     if (typeof onSubmit === 'function') { | ||||
|       onSubmit(formData.dataType); | ||||
|     } | ||||
|     // Navigate to CodeExtension page with the form data
 | ||||
|     navigate('/CodeExtension', { state: { formData } }); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div style={{ maxWidth: '600px', margin: '0 auto' }}> | ||||
|       <Typography variant="h4" gutterBottom>Add Item</Typography> | ||||
|       <form onSubmit={handleSubmit}> | ||||
|         <div> | ||||
|           <Select | ||||
|             label="Type" | ||||
|             name="type" | ||||
|             value={formData.type} | ||||
|             onChange={handleChange} | ||||
|             fullWidth | ||||
|             required | ||||
|           > | ||||
|             <MenuItem value="Header">Header</MenuItem> | ||||
|             <MenuItem value="Line">Line</MenuItem> | ||||
|           </Select> | ||||
|         </div> | ||||
|         <div> | ||||
|           <TextField | ||||
|             label="Field Name" | ||||
|             name="fieldName" | ||||
|             value={formData.fieldName} | ||||
|             onChange={handleChange} | ||||
|             fullWidth | ||||
|             required | ||||
|           /> | ||||
|         </div> | ||||
|         <div> | ||||
|           <Select | ||||
|             label="Mapping" | ||||
|             name="mapping" | ||||
|             value={formData.mapping} | ||||
|             onChange={handleChange} | ||||
|             fullWidth | ||||
|             required | ||||
|           > | ||||
|             {[...Array(15).keys()].map(num => ( | ||||
|               <MenuItem key={num + 1} value={`EXTN${num + 1}`}>{`EXTN${num + 1}`}</MenuItem> | ||||
|             ))} | ||||
|           </Select> | ||||
|         </div> | ||||
|         <div> | ||||
|           <Select | ||||
|             label="Data Type" | ||||
|             name="dataType" | ||||
|             value={formData.dataType} | ||||
|             onChange={handleChange} | ||||
|             fullWidth | ||||
|             required | ||||
|           > | ||||
|             <MenuItem value="textfield">Textfield</MenuItem> | ||||
|             <MenuItem value="longtext">Longtext</MenuItem> | ||||
|             <MenuItem value="date">Date</MenuItem> | ||||
|             <MenuItem value="checkbox">Checkbox</MenuItem> | ||||
|             <MenuItem value="radiobutton">Radiobutton</MenuItem> | ||||
|             <MenuItem value="autocomplete">Autocomplete</MenuItem> | ||||
|           </Select> | ||||
|         </div> | ||||
|         <Button type="submit" variant="contained" sx={{ mt: 2 }}>Submit</Button> | ||||
|       </form> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default Extension; | ||||
|  | ||||
| @ -1,217 +1,217 @@ | ||||
| import React, { useState } from "react"; | ||||
| import { useNavigate } from "react-router-dom"; | ||||
| import { v4 as uuidv4 } from "uuid"; | ||||
| 
 | ||||
| function DynamicForm() { | ||||
|   const [components, setComponents] = useState([ | ||||
|     { | ||||
|       id: uuidv4(), | ||||
|       label: "", | ||||
|       type: "", | ||||
|       mapping: "", | ||||
|       readonly: false, | ||||
|       values: "", | ||||
|     }, | ||||
|   ]); | ||||
|   const [formDetails, setFormDetails] = useState({ | ||||
|     formName: "", | ||||
|     formDescription: "", | ||||
|     relatedTo: "", | ||||
|     pageEvent: "", | ||||
|     buttonName: "", | ||||
|   }); | ||||
|   const navigate = useNavigate(); | ||||
| 
 | ||||
|   const handleFormChange = (e) => { | ||||
|     const { name, value } = e.target; | ||||
|     setFormDetails({ ...formDetails, [name]: value }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleComponentChange = (index, field, value) => { | ||||
|     const updatedComponents = components.map((component, i) => | ||||
|       i === index ? { ...component, [field]: value } : component | ||||
|     ); | ||||
|     setComponents(updatedComponents); | ||||
|   }; | ||||
| 
 | ||||
|   const addComponent = () => { | ||||
|     setComponents([ | ||||
|       ...components, | ||||
|       { | ||||
|         id: uuidv4(), | ||||
|         label: "", | ||||
|         type: "", | ||||
|         mapping: "", | ||||
|         readonly: false, | ||||
|         values: "", | ||||
|       }, | ||||
|     ]); | ||||
|   }; | ||||
| 
 | ||||
|   const removeComponent = (index) => { | ||||
|     setComponents(components.filter((_, i) => i !== index)); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSubmit = (e) => { | ||||
|     e.preventDefault(); | ||||
|     const formData = { ...formDetails, components }; | ||||
|     navigate("/Dynamictable", { state: { formData } }); // Navigate to DynamicTable with formData
 | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="p-5 min-h-screen"> | ||||
|       <h1 className="text-3xl font-bold text-center text-white bg-gray-400 mb-8 p-3"> | ||||
|         Dynamic Form Setup | ||||
|       </h1> | ||||
|       <form onSubmit={handleSubmit} className="space-y-6"> | ||||
|         <div className="grid grid-cols-1 md:grid-cols-3 gap-6"> | ||||
|           <div className="flex flex-col"> | ||||
|             <label className="text-gray-700">Form Name</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               name="formName" | ||||
|               value={formDetails.formName} | ||||
|               onChange={handleFormChange} | ||||
|               className="mt-1 p-2 border rounded" | ||||
|             /> | ||||
|           </div> | ||||
|           <div className="flex flex-col"> | ||||
|             <label className="text-gray-700">Form Description</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               name="formDescription" | ||||
|               value={formDetails.formDescription} | ||||
|               onChange={handleFormChange} | ||||
|               className="mt-1 p-2 border rounded" | ||||
|             /> | ||||
|           </div> | ||||
|           <div className="flex flex-col"> | ||||
|             <label className="text-gray-700">Related To</label> | ||||
|             <select | ||||
|               name="relatedTo" | ||||
|               value={formDetails.relatedTo} | ||||
|               onChange={handleFormChange} | ||||
|               className="mt-1 p-2 border rounded" | ||||
|             > | ||||
|               <option value=""> | ||||
|                 <em>None</em> | ||||
|               </option> | ||||
|               <option value="Menu">Menu</option> | ||||
|               <option value="Related to">Related to</option> | ||||
|             </select> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className="grid grid-cols-1 md:grid-cols-2 gap-6"> | ||||
|           <div className="flex flex-col"> | ||||
|             <label className="text-gray-700">Page Event</label> | ||||
|             <select | ||||
|               name="pageEvent" | ||||
|               value={formDetails.pageEvent} | ||||
|               onChange={handleFormChange} | ||||
|               className="mt-1 p-2 border rounded" | ||||
|             > | ||||
|               <option value="Onclick">Onclick</option> | ||||
|               <option value="Onblur">Onblur</option> | ||||
|             </select> | ||||
|           </div> | ||||
|           <div className="flex flex-col"> | ||||
|             <label className="text-gray-700">Button Name</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               name="buttonName" | ||||
|               value={formDetails.buttonName} | ||||
|               onChange={handleFormChange} | ||||
|               className="mt-1 p-2 border rounded" | ||||
|             /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <h2 className="text-2xl font-semibold text-gray-700 mt-8"> | ||||
|           Component Details | ||||
|         </h2> | ||||
|         {components.map((component, index) => ( | ||||
|           <div | ||||
|             key={component.id} | ||||
|             className="grid grid-cols-1 md:grid-cols-5 gap-4 items-center mt-4" | ||||
|           > | ||||
|             <input | ||||
|               type="text" | ||||
|               placeholder="Label" | ||||
|               value={component.label} | ||||
|               onChange={(e) => | ||||
|                 handleComponentChange(index, "label", e.target.value) | ||||
|               } | ||||
|               className="p-2 border rounded col-span-1" | ||||
|             /> | ||||
|             <select | ||||
|               value={component.type} | ||||
|               onChange={(e) => | ||||
|                 handleComponentChange(index, "type", e.target.value) | ||||
|               } | ||||
|               className="p-2 border rounded col-span-1" | ||||
|             > | ||||
|               <option value=""> | ||||
|                 <em>None</em> | ||||
|               </option> | ||||
|               <option value="textfield">TextField</option> | ||||
|               <option value="checkbox">Checkbox</option> | ||||
|               <option value="select">Select</option> | ||||
|             </select> | ||||
|             <input | ||||
|               type="text" | ||||
|               placeholder="Mapping" | ||||
|               value={component.mapping} | ||||
|               onChange={(e) => | ||||
|                 handleComponentChange(index, "mapping", e.target.value) | ||||
|               } | ||||
|               className="p-2 border rounded col-span-1" | ||||
|             /> | ||||
|             <div className="flex items-center"> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={component.readonly} | ||||
|                 onChange={(e) => | ||||
|                   handleComponentChange(index, "readonly", e.target.checked) | ||||
|                 } | ||||
|                 className="mr-2" | ||||
|               /> | ||||
|               <label>Readonly</label> | ||||
|             </div> | ||||
|             <input | ||||
|               type="text" | ||||
|               placeholder="Enter Values" | ||||
|               value={component.values} | ||||
|               onChange={(e) => | ||||
|                 handleComponentChange(index, "values", e.target.value) | ||||
|               } | ||||
|               className="p-2 border rounded col-span-1" | ||||
|             /> | ||||
|             <button | ||||
|               type="button" | ||||
|               onClick={() => removeComponent(index)} | ||||
|               className="text-red-500 hover:text-red-700" | ||||
|             > | ||||
|               {/* <DeleteIcon /> */} | ||||
|             </button> | ||||
|           </div> | ||||
|         ))} | ||||
|         <div className="flex justify-between mt-6"> | ||||
|           <button | ||||
|             type="button" | ||||
|             onClick={addComponent} | ||||
|             className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600" | ||||
|           > | ||||
|             Add Component | ||||
|           </button> | ||||
|           <button | ||||
|             type="submit" | ||||
|             className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600" | ||||
|           > | ||||
|             Submit | ||||
|           </button> | ||||
|         </div> | ||||
|       </form> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default DynamicForm; | ||||
| import React, { useState } from "react"; | ||||
| import { useNavigate } from "react-router-dom"; | ||||
| import { v4 as uuidv4 } from "uuid"; | ||||
| 
 | ||||
| function Form() { | ||||
|   const [components, setComponents] = useState([ | ||||
|     { | ||||
|       id: uuidv4(), | ||||
|       label: "", | ||||
|       type: "", | ||||
|       mapping: "", | ||||
|       readonly: false, | ||||
|       values: "", | ||||
|     }, | ||||
|   ]); | ||||
|   const [formDetails, setFormDetails] = useState({ | ||||
|     formName: "", | ||||
|     formDescription: "", | ||||
|     relatedTo: "", | ||||
|     pageEvent: "", | ||||
|     buttonName: "", | ||||
|   }); | ||||
|   const navigate = useNavigate(); | ||||
| 
 | ||||
|   const handleFormChange = (e) => { | ||||
|     const { name, value } = e.target; | ||||
|     setFormDetails({ ...formDetails, [name]: value }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleComponentChange = (index, field, value) => { | ||||
|     const updatedComponents = components.map((component, i) => | ||||
|       i === index ? { ...component, [field]: value } : component | ||||
|     ); | ||||
|     setComponents(updatedComponents); | ||||
|   }; | ||||
| 
 | ||||
|   const addComponent = () => { | ||||
|     setComponents([ | ||||
|       ...components, | ||||
|       { | ||||
|         id: uuidv4(), | ||||
|         label: "", | ||||
|         type: "", | ||||
|         mapping: "", | ||||
|         readonly: false, | ||||
|         values: "", | ||||
|       }, | ||||
|     ]); | ||||
|   }; | ||||
| 
 | ||||
|   const removeComponent = (index) => { | ||||
|     setComponents(components.filter((_, i) => i !== index)); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSubmit = (e) => { | ||||
|     e.preventDefault(); | ||||
|     const formData = { ...formDetails, components }; | ||||
|     navigate("/Dynamictable", { state: { formData } }); // Navigate to DynamicTable with formData
 | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="p-5 min-h-screen"> | ||||
|       <h1 className="text-3xl font-bold text-center text-white bg-gray-400 mb-8 p-3"> | ||||
|         Dynamic Form Setup | ||||
|       </h1> | ||||
|       <form onSubmit={handleSubmit} className="space-y-6"> | ||||
|         <div className="grid grid-cols-1 md:grid-cols-3 gap-6"> | ||||
|           <div className="flex flex-col"> | ||||
|             <label className="text-gray-700">Form Name</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               name="formName" | ||||
|               value={formDetails.formName} | ||||
|               onChange={handleFormChange} | ||||
|               className="mt-1 p-2 border rounded" | ||||
|             /> | ||||
|           </div> | ||||
|           <div className="flex flex-col"> | ||||
|             <label className="text-gray-700">Form Description</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               name="formDescription" | ||||
|               value={formDetails.formDescription} | ||||
|               onChange={handleFormChange} | ||||
|               className="mt-1 p-2 border rounded" | ||||
|             /> | ||||
|           </div> | ||||
|           <div className="flex flex-col"> | ||||
|             <label className="text-gray-700">Related To</label> | ||||
|             <select | ||||
|               name="relatedTo" | ||||
|               value={formDetails.relatedTo} | ||||
|               onChange={handleFormChange} | ||||
|               className="mt-1 p-2 border rounded" | ||||
|             > | ||||
|               <option value=""> | ||||
|                 <em>None</em> | ||||
|               </option> | ||||
|               <option value="Menu">Menu</option> | ||||
|               <option value="Related to">Related to</option> | ||||
|             </select> | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className="grid grid-cols-1 md:grid-cols-2 gap-6"> | ||||
|           <div className="flex flex-col"> | ||||
|             <label className="text-gray-700">Page Event</label> | ||||
|             <select | ||||
|               name="pageEvent" | ||||
|               value={formDetails.pageEvent} | ||||
|               onChange={handleFormChange} | ||||
|               className="mt-1 p-2 border rounded" | ||||
|             > | ||||
|               <option value="Onclick">Onclick</option> | ||||
|               <option value="Onblur">Onblur</option> | ||||
|             </select> | ||||
|           </div> | ||||
|           <div className="flex flex-col"> | ||||
|             <label className="text-gray-700">Button Name</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               name="buttonName" | ||||
|               value={formDetails.buttonName} | ||||
|               onChange={handleFormChange} | ||||
|               className="mt-1 p-2 border rounded" | ||||
|             /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <h2 className="text-2xl font-semibold text-gray-700 mt-8"> | ||||
|           Component Details | ||||
|         </h2> | ||||
|         {components.map((component, index) => ( | ||||
|           <div | ||||
|             key={component.id} | ||||
|             className="grid grid-cols-1 md:grid-cols-5 gap-4 items-center mt-4" | ||||
|           > | ||||
|             <input | ||||
|               type="text" | ||||
|               placeholder="Label" | ||||
|               value={component.label} | ||||
|               onChange={(e) => | ||||
|                 handleComponentChange(index, "label", e.target.value) | ||||
|               } | ||||
|               className="p-2 border rounded col-span-1" | ||||
|             /> | ||||
|             <select | ||||
|               value={component.type} | ||||
|               onChange={(e) => | ||||
|                 handleComponentChange(index, "type", e.target.value) | ||||
|               } | ||||
|               className="p-2 border rounded col-span-1" | ||||
|             > | ||||
|               <option value=""> | ||||
|                 <em>None</em> | ||||
|               </option> | ||||
|               <option value="textfield">TextField</option> | ||||
|               <option value="checkbox">Checkbox</option> | ||||
|               <option value="select">Select</option> | ||||
|             </select> | ||||
|             <input | ||||
|               type="text" | ||||
|               placeholder="Mapping" | ||||
|               value={component.mapping} | ||||
|               onChange={(e) => | ||||
|                 handleComponentChange(index, "mapping", e.target.value) | ||||
|               } | ||||
|               className="p-2 border rounded col-span-1" | ||||
|             /> | ||||
|             <div className="flex items-center"> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={component.readonly} | ||||
|                 onChange={(e) => | ||||
|                   handleComponentChange(index, "readonly", e.target.checked) | ||||
|                 } | ||||
|                 className="mr-2" | ||||
|               /> | ||||
|               <label>Readonly</label> | ||||
|             </div> | ||||
|             <input | ||||
|               type="text" | ||||
|               placeholder="Enter Values" | ||||
|               value={component.values} | ||||
|               onChange={(e) => | ||||
|                 handleComponentChange(index, "values", e.target.value) | ||||
|               } | ||||
|               className="p-2 border rounded col-span-1" | ||||
|             /> | ||||
|             <button | ||||
|               type="button" | ||||
|               onClick={() => removeComponent(index)} | ||||
|               className="text-red-500 hover:text-red-700" | ||||
|             > | ||||
|               {/* <DeleteIcon /> */} | ||||
|             </button> | ||||
|           </div> | ||||
|         ))} | ||||
|         <div className="flex justify-between mt-6"> | ||||
|           <button | ||||
|             type="button" | ||||
|             onClick={addComponent} | ||||
|             className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600" | ||||
|           > | ||||
|             Add Component | ||||
|           </button> | ||||
|           <button | ||||
|             type="submit" | ||||
|             className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600" | ||||
|           > | ||||
|             Submit | ||||
|           </button> | ||||
|         </div> | ||||
|       </form> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default Form; | ||||
|  | ||||
| @ -1,50 +1,50 @@ | ||||
| /* HomePage.css */ | ||||
| 
 | ||||
| .container { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|   height: 100vh; | ||||
| } | ||||
| 
 | ||||
| .heading { | ||||
|   font-size: 24px; | ||||
|   margin-bottom: 20px; | ||||
| } | ||||
| 
 | ||||
| .card-container { | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|   flex-wrap: wrap; /* Allow cards to wrap to the next line */ | ||||
|   margin-top: 20px; | ||||
| } | ||||
| 
 | ||||
| .card { | ||||
|   background-color: #9ee2f5; | ||||
|   padding: 40px; | ||||
|   border-radius: 8px; | ||||
|   box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); | ||||
|   width: 30%; /* Adjust card width for larger screens */ | ||||
|   margin: 10px; | ||||
| } | ||||
| 
 | ||||
| .chart-container { | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|   margin-top: 20px; | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 768px) { | ||||
|   .card { | ||||
|     width: 45%; /* Adjust card width for screens up to 768px */ | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 480px) { | ||||
|   .card { | ||||
|     width: 100%; /* Make cards occupy full width on screens up to 480px */ | ||||
|   } | ||||
| } | ||||
| /* HomePage.css */ | ||||
| 
 | ||||
| .container { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|   height: 100vh; | ||||
| } | ||||
| 
 | ||||
| .heading { | ||||
|   font-size: 24px; | ||||
|   margin-bottom: 20px; | ||||
| } | ||||
| 
 | ||||
| .card-container { | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|   flex-wrap: wrap; /* Allow cards to wrap to the next line */ | ||||
|   margin-top: 20px; | ||||
| } | ||||
| 
 | ||||
| .card { | ||||
|   background-color: #9ee2f5; | ||||
|   padding: 40px; | ||||
|   border-radius: 8px; | ||||
|   box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); | ||||
|   width: 30%; /* Adjust card width for larger screens */ | ||||
|   margin: 10px; | ||||
| } | ||||
| 
 | ||||
| .chart-container { | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|   margin-top: 20px; | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 768px) { | ||||
|   .card { | ||||
|     width: 45%; /* Adjust card width for screens up to 768px */ | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 480px) { | ||||
|   .card { | ||||
|     width: 100%; /* Make cards occupy full width on screens up to 480px */ | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,37 +1,113 @@ | ||||
| // HomePage.js
 | ||||
| 
 | ||||
| import React from 'react'; | ||||
| import { BarChart } from '@mui/x-charts/BarChart'; // Import BarChart component
 | ||||
| 
 | ||||
| const Card = ({ index }) => { | ||||
|   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"> | ||||
|       <h3 className="text-lg font-semibold mb-2">INDEX {index}</h3> | ||||
|       <p className="text-gray-600">{index}.</p> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| const HomePage = () => { | ||||
|   return ( | ||||
|     <div className="min-h-screen flex flex-col items-center justify-center bg-gray-100 p-4"> | ||||
|       <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} /> | ||||
|         <Card index={2} /> | ||||
|         <Card index={3} /> | ||||
|       </div> | ||||
|       <div className="w-full mt-8 flex justify-center"> | ||||
|         {/* Add BarChart component */} | ||||
|         <BarChart | ||||
|           xAxis={[{ scaleType: 'band', data: ['group A', 'group B', 'group C'] }]} | ||||
|           series={[{ data: [4, 3, 5] }, { data: [1, 6, 3] }, { data: [2, 5, 6] }]} | ||||
|           width={700} | ||||
|           height={400} | ||||
|         /> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default HomePage; | ||||
| // HomePage.js
 | ||||
| 
 | ||||
| import React from 'react'; | ||||
| import { FaUsers, FaCog, FaChartBar, FaShieldAlt } from 'react-icons/fa'; | ||||
| 
 | ||||
| const StatCard = ({ icon: Icon, title, value, color }) => ( | ||||
|   <div className="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-all duration-200"> | ||||
|     <div className="flex items-center space-x-4"> | ||||
|       <div className={`p-3 rounded-lg ${color}`}> | ||||
|         <Icon className="w-6 h-6 text-white" /> | ||||
|       </div> | ||||
|       <div> | ||||
|         <h3 className="text-gray-500 text-sm font-medium">{title}</h3> | ||||
|         <p className="text-2xl font-bold text-gray-800">{value}</p> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| ); | ||||
| 
 | ||||
| const HomePage = () => { | ||||
|   return ( | ||||
|     <div className="space-y-6"> | ||||
|       <div className="flex items-center justify-between"> | ||||
|         <h1 className="text-3xl font-bold text-gray-800">Welcome Back!</h1> | ||||
|         <div className="text-sm text-gray-500">Last updated: {new Date().toLocaleDateString()}</div> | ||||
|       </div> | ||||
| 
 | ||||
|       {/* Stats Grid */} | ||||
|       <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> | ||||
|         <StatCard | ||||
|           icon={FaUsers} | ||||
|           title="Total Users" | ||||
|           value="1,234" | ||||
|           color="bg-gradient-to-r from-purple-500 to-indigo-500" | ||||
|         /> | ||||
|         <StatCard | ||||
|           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'); | ||||
| .custom-header, .custom-cell { | ||||
|   font-family: 'PT Serif", serif ';  | ||||
|    | ||||
|   font-style: normal; | ||||
|   font-weight: bold; | ||||
| } | ||||
| @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 { | ||||
|   font-family: 'PT Serif", serif ';  | ||||
|    | ||||
|   font-style: normal; | ||||
|   font-weight: bold; | ||||
| } | ||||
|  | ||||
| @ -1,162 +1,161 @@ | ||||
| import React, { useState, useEffect, useRef } from 'react'; | ||||
| import { Box, Button } from '@mui/material'; | ||||
| import { DataGrid, GridToolbarContainer } from '@mui/x-data-grid'; | ||||
| import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||||
| import { faEllipsisV } from '@fortawesome/free-solid-svg-icons'; | ||||
| 
 | ||||
| function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) { | ||||
|   const handleGoToPage1 = () => { | ||||
|     if (apiRef.current) { | ||||
|       apiRef.current.setPage(1); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <GridToolbarContainer> | ||||
|       <Button onClick={handleGoToPage1}>Go to page 1</Button> | ||||
|       <Button onClick={handleModal}>+</Button>  | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function MenuAccessControl() { | ||||
|   const [menuItems, setMenuItems] = useState([]); | ||||
|   const [selectedMenuItem, setSelectedMenuItem] = useState(null); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const [isUpdateModalOpen, setIsUpdateModalOpen] = useState(false); | ||||
|   const [newMenuItem, setNewMenuItem] = useState({ | ||||
|     // Define initial values for the new menu item in the modal
 | ||||
|     No: '', | ||||
|     menuItemname: '', | ||||
|     view: '', | ||||
|     create: '', | ||||
|     edit: '', | ||||
|     delete: '', | ||||
|     query: '', | ||||
|     export: [], | ||||
|   }); | ||||
|   const apiRef = useRef(null); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       try { | ||||
|         const response = await fetch(''); | ||||
|         const data = await response.json(); | ||||
|          | ||||
|         // Set unique IDs for each menu item
 | ||||
|         const menuItemsWithIds = data.map((menuItem, index) => ({ ...menuItem, id: index + 1 })); | ||||
|         setMenuItems(menuItemsWithIds); | ||||
|       } catch (error) { | ||||
|         console.error('Error fetching data:', error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (menuItemId) => { | ||||
|     setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); | ||||
|   }; | ||||
| 
 | ||||
|   const handleDelete = (menuItemId) => { | ||||
|     // Implement delete logic here
 | ||||
|     console.log('Delete menu item with ID:', menuItemId); | ||||
|   }; | ||||
| 
 | ||||
|   const handleUpdate = (menuItem) => { | ||||
|     // Implement update logic here
 | ||||
|     console.log('Update menu item:', menuItem); | ||||
|   }; | ||||
| 
 | ||||
|   const handleModal = () => { | ||||
|     setIsModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   const handleModalSave = () => { | ||||
|     // Implement save logic for adding a new menu item here
 | ||||
|     setIsModalOpen(false); | ||||
|   }; | ||||
| 
 | ||||
|   const handleUpdateSave = () => { | ||||
|     // Implement save logic for updating a menu item here
 | ||||
|     setIsUpdateModalOpen(false); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { 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: 'view', headerName: 'View', 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: 'delete', headerName: 'Delete', 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: 'actions', | ||||
|       headerName: 'Actions', | ||||
|       width: 100, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div> | ||||
|           <div className="three-dots" onClick={() => handleThreeDotsClick(row.menuItemId)}> | ||||
|             <FontAwesomeIcon icon={faEllipsisV} /> | ||||
|           </div> | ||||
|           {selectedMenuItem === row.menuItemId && ( | ||||
|             <div className="popover"> | ||||
|               <button onClick={() => handleDelete(row.menuItemId)}>Delete</button> | ||||
|               <button onClick={() => handleUpdate(row)}>Update</button> | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ), | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   return ( | ||||
|     <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='text-center text-3xl text-white bg-gray-400 p-2 rounded-lg'>Menu Access Control</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%' }} > | ||||
|         <DataGrid | ||||
|           rows={menuItems} | ||||
|           columns={columns} | ||||
|           components={{ | ||||
|             Toolbar: () => ( | ||||
|               <CustomToolbar | ||||
|                 apiRef={apiRef} | ||||
|                 handleThreeDotsClick={handleThreeDotsClick} | ||||
|                 handleModal={handleModal} | ||||
|               /> | ||||
|             ), | ||||
|           }} | ||||
|           pageSize={10} | ||||
|           onGridReady={(gridApi) => { | ||||
|             apiRef.current = gridApi; | ||||
|           }} | ||||
|           className="bg-gray-400" | ||||
|         /> | ||||
|       </Box> | ||||
|       {/* Your modals and other components */} | ||||
|       {isModalOpen && ( | ||||
|         <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"> | ||||
|             <h2 className="text-xl font-bold mb-4">Add New Menu Item</h2> | ||||
|             {/* Modal content here */} | ||||
|             <Button onClick={() => setIsModalOpen(false)}>Close</Button> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|       {isUpdateModalOpen && ( | ||||
|         <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"> | ||||
|             <h2 className="text-xl font-bold mb-4">Update Menu Item</h2> | ||||
|             {/* Modal content here */} | ||||
|             <Button onClick={() => setIsUpdateModalOpen(false)}>Close</Button> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default MenuAccessControl; | ||||
|  // eslint-disable-next-line 
 | ||||
| import React, { useState, useEffect, useRef } from 'react'; | ||||
| import { Box, Button } from '@mui/material'; | ||||
| import { DataGrid, GridToolbarContainer } from '@mui/x-data-grid'; | ||||
| import { BsThreeDotsVertical } from 'react-icons/bs'; // Importing react-icons
 | ||||
| 
 | ||||
| function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) { | ||||
|   const handleGoToPage1 = () => { | ||||
|     if (apiRef.current) { | ||||
|       apiRef.current.setPage(1); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <GridToolbarContainer> | ||||
|       <Button onClick={handleGoToPage1}>Go to page 1</Button> | ||||
|       <Button onClick={handleModal}>+</Button>  | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function MenuAccessControl() { | ||||
|   const [menuItems, setMenuItems] = useState([]); | ||||
|   const [selectedMenuItem, setSelectedMenuItem] = useState(null); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const [isUpdateModalOpen, setIsUpdateModalOpen] = useState(false); | ||||
|   // const [newMenuItem, setNewMenuItem] = useState({
 | ||||
|   //   No: '',
 | ||||
|   //   menuItemname: '',
 | ||||
|   //   view: '',
 | ||||
|   //   create: '',
 | ||||
|   //   edit: '',
 | ||||
|   //   delete: '',
 | ||||
|   //   query: '',
 | ||||
|   //   export: [],
 | ||||
|   // });
 | ||||
|   const apiRef = useRef(null); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       try { | ||||
|         const response = await fetch(''); | ||||
|         const data = await response.json(); | ||||
|          | ||||
|         // Set unique IDs for each menu item
 | ||||
|         const menuItemsWithIds = data.map((menuItem, index) => ({ ...menuItem, id: index + 1 })); | ||||
|         setMenuItems(menuItemsWithIds); | ||||
|       } catch (error) { | ||||
|         console.error('Error fetching data:', error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (menuItemId) => { | ||||
|     setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); | ||||
|   }; | ||||
| 
 | ||||
|   const handleDelete = (menuItemId) => { | ||||
|     // Implement delete logic here
 | ||||
|     console.log('Delete menu item with ID:', menuItemId); | ||||
|   }; | ||||
| 
 | ||||
|   const handleUpdate = (menuItem) => { | ||||
|     // Implement update logic here
 | ||||
|     console.log('Update menu item:', menuItem); | ||||
|   }; | ||||
| 
 | ||||
|   const handleModal = () => { | ||||
|     setIsModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   // const handleModalSave = () => {
 | ||||
|   //   // Implement save logic for adding a new menu item here
 | ||||
|   //   setIsModalOpen(false);
 | ||||
|   // };
 | ||||
| 
 | ||||
|   // const handleUpdateSave = () => {
 | ||||
|   //   // Implement save logic for updating a menu item here
 | ||||
|   //   setIsUpdateModalOpen(false);
 | ||||
|   // };
 | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { 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: 'view', headerName: 'View', 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: 'delete', headerName: 'Delete', 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: 'actions', | ||||
|       headerName: 'Actions', | ||||
|       width: 100, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div> | ||||
|           <div className="three-dots" onClick={() => handleThreeDotsClick(row.menuItemId)}> | ||||
|             <BsThreeDotsVertical /> {/* Using react-icons */} | ||||
|           </div> | ||||
|           {selectedMenuItem === row.menuItemId && ( | ||||
|             <div className="popover"> | ||||
|               <button onClick={() => handleDelete(row.menuItemId)}>Delete</button> | ||||
|               <button onClick={() => handleUpdate(row)}>Update</button> | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ), | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   return ( | ||||
|     <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='text-center text-3xl text-white bg-gray-400 p-2 rounded-lg'>Menu Access Control</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%' }} > | ||||
|         <DataGrid | ||||
|           rows={menuItems} | ||||
|           columns={columns} | ||||
|           components={{ | ||||
|             Toolbar: () => ( | ||||
|               <CustomToolbar | ||||
|                 apiRef={apiRef} | ||||
|                 handleThreeDotsClick={handleThreeDotsClick} | ||||
|                 handleModal={handleModal} | ||||
|               /> | ||||
|             ), | ||||
|           }} | ||||
|           pageSize={10} | ||||
|           onGridReady={(gridApi) => { | ||||
|             apiRef.current = gridApi; | ||||
|           }} | ||||
|           className="bg-gray-400" | ||||
|         /> | ||||
|       </Box> | ||||
|       {/* Your modals and other components */} | ||||
|       {isModalOpen && ( | ||||
|         <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"> | ||||
|             <h2 className="text-xl font-bold mb-4">Add New Menu Item</h2> | ||||
|             {/* Modal content here */} | ||||
|             <Button onClick={() => setIsModalOpen(false)}>Close</Button> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|       {isUpdateModalOpen && ( | ||||
|         <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"> | ||||
|             <h2 className="text-xl font-bold mb-4">Update Menu Item</h2> | ||||
|             {/* Modal content here */} | ||||
|             <Button onClick={() => setIsUpdateModalOpen(false)}>Close</Button> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| 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'); | ||||
| .custom-header, .custom-cell { | ||||
|   font-family: 'PT Serif", serif ';  | ||||
|    | ||||
|   font-style: normal; | ||||
|   font-weight: bold; | ||||
| } | ||||
| @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 { | ||||
|   font-family: 'PT Serif", serif ';  | ||||
|    | ||||
|   font-style: normal; | ||||
|   font-weight: bold; | ||||
| } | ||||
|  | ||||
| @ -1,180 +1,178 @@ | ||||
| import React, { useState, useEffect, useRef } from "react"; | ||||
| import { Box, Button } from "@mui/material"; | ||||
| import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; | ||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||
| import { faEllipsisV } from "@fortawesome/free-solid-svg-icons"; | ||||
| import "./MenuMaintance.css"; | ||||
| 
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) { | ||||
|   const handleGoToPage1 = () => { | ||||
|     if (apiRef.current) { | ||||
|       apiRef.current.setPage(1); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <GridToolbarContainer> | ||||
|       <Button onClick={handleGoToPage1}>Go to page 1</Button> | ||||
|       <Button onClick={handleModal}>+</Button> | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function MenuMaintenance() { | ||||
|   const [menuItems, setMenuItems] = useState([]); | ||||
|   const [selectedMenuItem, setSelectedMenuItem] = useState(null); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const apiRef = useRef(null); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("token"); | ||||
|       try { | ||||
|         const response = await fetch(`${api}/api1/submenu1`, { | ||||
|           headers: { | ||||
|             Authorization: `Bearer ${token}`, | ||||
|           }, | ||||
|         }); | ||||
| 
 | ||||
|         if (!response.ok) { | ||||
|           throw new Error(`HTTP error! status: ${response.status}`); | ||||
|         } | ||||
| 
 | ||||
|         const data = await response.json(); | ||||
|         // Flatten the nested subMenus array
 | ||||
|         const flattenedData = data.flatMap((menuItem) => [ | ||||
|           menuItem, | ||||
|           ...menuItem.subMenus, | ||||
|         ]); | ||||
|         // Set unique IDs for each menu item
 | ||||
|         const menuItemsWithIds = flattenedData.map((menuItem, index) => ({ | ||||
|           ...menuItem, | ||||
|           id: index + 1, | ||||
|         })); | ||||
|         setMenuItems(menuItemsWithIds); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (menuItemId) => { | ||||
|     setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { | ||||
|       field: "menuItemId", | ||||
|       headerName: "Menu Item ID", | ||||
|       width: 200, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "menuItemDesc", | ||||
|       headerName: "Menu Item Description", | ||||
|       width: 250, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "moduleName", | ||||
|       headerName: "Module Name", | ||||
|       width: 200, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "main_menu_action_name", | ||||
|       headerName: "Main Menu Action", | ||||
|       width: 200, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "main_menu_icon_name", | ||||
|       headerName: "Main Menu Icon", | ||||
|       width: 200, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "actions", | ||||
|       headerName: "Actions", | ||||
|       width: 150, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div className="relative"> | ||||
|           <div | ||||
|             className="three-dots" | ||||
|             onClick={() => handleThreeDotsClick(row.menuItemId)} | ||||
|           > | ||||
|             <FontAwesomeIcon | ||||
|               icon={faEllipsisV} | ||||
|               className="cursor-pointer text-gray-800 hover:text-gray-600" | ||||
|             /> | ||||
|           </div> | ||||
|           {selectedMenuItem === row.menuItemId && ( | ||||
|             <div className="absolute bg-white border border-gray-200 shadow-lg p-4 mt-2 rounded-lg"> | ||||
|               {/* Implement your actions buttons here */} | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ), | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="flex flex-col items-center justify-center min-h-screen bg-gray-100"> | ||||
|       <div className="text-3xl text-center text-black mb-3 bg-slate-400"> | ||||
|         Menu Maintenance | ||||
|       </div> | ||||
|       <Box | ||||
|         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} | ||||
|           columns={columns} | ||||
|           components={{ | ||||
|             Toolbar: () => ( | ||||
|               <CustomToolbar | ||||
|                 apiRef={apiRef} | ||||
|                 handleThreeDotsClick={handleThreeDotsClick} | ||||
|                 handleModal={() => setIsModalOpen(true)} | ||||
|               /> | ||||
|             ), | ||||
|           }} | ||||
|           pageSize={10} | ||||
|           onGridReady={(gridApi) => { | ||||
|             apiRef.current = gridApi; | ||||
|           }} | ||||
|           sx={{ | ||||
|             "& .MuiDataGrid-columnHeaders": { | ||||
|               backgroundColor: "rgba(107, 114, 128, 0.5)", // Tailwind CSS bg-gray-400 with opacity
 | ||||
|             }, | ||||
|             "& .MuiDataGrid-columnHeaderTitle": { | ||||
|               fontWeight: "bold", | ||||
|             }, | ||||
|           }} | ||||
|           className=" border border-gray-200 shadow-lg rounded-lg bg-gray-400" | ||||
|         /> | ||||
|       </Box> | ||||
|       {/* Your modals and other components */} | ||||
|       {isModalOpen && ( | ||||
|         <div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"> | ||||
|           <div className="bg-white p-8 rounded-lg shadow-lg"> | ||||
|             <h2 className="text-xl font-bold mb-4">Modal Title</h2> | ||||
|             {/* Modal content here */} | ||||
|             <Button onClick={() => setIsModalOpen(false)}>Close</Button> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default MenuMaintenance; | ||||
| import React, { useState, useEffect, useRef } from "react"; | ||||
| import { Box, Button } from "@mui/material"; | ||||
| import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; | ||||
| import { BsThreeDotsVertical } from "react-icons/bs"; // Importing react-icons
 | ||||
| import "./MenuMaintance.css"; | ||||
| 
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) { | ||||
|   const handleGoToPage1 = () => { | ||||
|     if (apiRef.current) { | ||||
|       apiRef.current.setPage(1); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <GridToolbarContainer> | ||||
|       <Button onClick={handleGoToPage1}>Go to page 1</Button> | ||||
|       <Button onClick={handleModal}>+</Button> | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function MenuMaintenance() { | ||||
|   const [menuItems, setMenuItems] = useState([]); | ||||
|   const [selectedMenuItem, setSelectedMenuItem] = useState(null); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const apiRef = useRef(null); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("authToken"); | ||||
|       try { | ||||
|         const response = await fetch(`${api}/api1/submenu1`, { | ||||
|           headers: { | ||||
|             Authorization: `Bearer ${token}`, | ||||
|           }, | ||||
|         }); | ||||
| 
 | ||||
|         if (!response.ok) { | ||||
|           throw new Error(`HTTP error! status: ${response.status}`); | ||||
|         } | ||||
| 
 | ||||
|         const data = await response.json(); | ||||
|         // Flatten the nested subMenus array
 | ||||
|         const flattenedData = data.flatMap((menuItem) => [ | ||||
|           menuItem, | ||||
|           ...menuItem.subMenus, | ||||
|         ]); | ||||
|         // Set unique IDs for each menu item
 | ||||
|         const menuItemsWithIds = flattenedData.map((menuItem, index) => ({ | ||||
|           ...menuItem, | ||||
|           id: index + 1, | ||||
|         })); | ||||
|         setMenuItems(menuItemsWithIds); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (menuItemId) => { | ||||
|     setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { | ||||
|       field: "menuItemId", | ||||
|       headerName: "Menu Item ID", | ||||
|       width: 200, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "menuItemDesc", | ||||
|       headerName: "Menu Item Description", | ||||
|       width: 250, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "moduleName", | ||||
|       headerName: "Module Name", | ||||
|       width: 200, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "main_menu_action_name", | ||||
|       headerName: "Main Menu Action", | ||||
|       width: 200, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "main_menu_icon_name", | ||||
|       headerName: "Main Menu Icon", | ||||
|       width: 200, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "actions", | ||||
|       headerName: "Actions", | ||||
|       width: 150, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div className="relative"> | ||||
|           <div | ||||
|             className="three-dots" | ||||
|             onClick={() => handleThreeDotsClick(row.menuItemId)} | ||||
|           > | ||||
|             <BsThreeDotsVertical | ||||
|               className="cursor-pointer text-gray-800 hover:text-gray-600" | ||||
|             /> | ||||
|           </div> | ||||
|           {selectedMenuItem === row.menuItemId && ( | ||||
|             <div className="absolute bg-white border border-gray-200 shadow-lg p-4 mt-2 rounded-lg"> | ||||
|               {/* Implement your actions buttons here */} | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ), | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="flex flex-col items-center justify-center min-h-screen bg-gray-100"> | ||||
|       <div className="text-3xl text-center text-black mb-3 bg-slate-400"> | ||||
|         Menu Maintenance | ||||
|       </div> | ||||
|       <Box | ||||
|         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} | ||||
|           columns={columns} | ||||
|           components={{ | ||||
|             Toolbar: () => ( | ||||
|               <CustomToolbar | ||||
|                 apiRef={apiRef} | ||||
|                 handleThreeDotsClick={handleThreeDotsClick} | ||||
|                 handleModal={() => setIsModalOpen(true)} | ||||
|               /> | ||||
|             ), | ||||
|           }} | ||||
|           pageSize={10} | ||||
|           onGridReady={(gridApi) => { | ||||
|             apiRef.current = gridApi; | ||||
|           }} | ||||
|           sx={{ | ||||
|             "& .MuiDataGrid-columnHeaders": { | ||||
|               backgroundColor: "rgba(107, 114, 128, 0.5)", // Tailwind CSS bg-gray-400 with opacity
 | ||||
|             }, | ||||
|             "& .MuiDataGrid-columnHeaderTitle": { | ||||
|               fontWeight: "bold", | ||||
|             }, | ||||
|           }} | ||||
|           className="border border-gray-200 shadow-lg rounded-lg bg-gray-400" | ||||
|         /> | ||||
|       </Box> | ||||
|       {/* Your modals and other components */} | ||||
|       {isModalOpen && ( | ||||
|         <div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"> | ||||
|           <div className="bg-white p-8 rounded-lg shadow-lg"> | ||||
|             <h2 className="text-xl font-bold mb-4">Modal Title</h2> | ||||
|             {/* Modal content here */} | ||||
|             <Button onClick={() => setIsModalOpen(false)}>Close</Button> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default MenuMaintenance; | ||||
|  | ||||
| @ -1,101 +1,101 @@ | ||||
| import React, { useState } from 'react'; | ||||
| import './Model.css'; | ||||
| 
 | ||||
| const Modal = ({ setNewUser, newUser, onSave }) => { | ||||
|   const [newUserState, setNewUserState] = useState(newUser); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
| 
 | ||||
|   const handleSave = () => { | ||||
|     const data = {  ...newUserState }; | ||||
|     onSave(data); // Pass the new data to the parent component
 | ||||
|     setIsModalOpen(false); // Close the modal after saving
 | ||||
|   }; | ||||
|    | ||||
| 
 | ||||
|   const handleClose = () => { | ||||
|     setIsModalOpen(false); | ||||
|   }; | ||||
| 
 | ||||
|   const handleOpenModal = () => { | ||||
|     setIsModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       <button onClick={handleOpenModal}>ADD ITEM</button> | ||||
| 
 | ||||
|       {isModalOpen && ( | ||||
|         <div className='modalWrapper'> | ||||
|           <div className='modal'> | ||||
|             <button className="closeBtn" onClick={handleClose}>X</button> | ||||
| 
 | ||||
|             <div className="input-group"> | ||||
|               <label htmlFor="userId">User ID:</label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="userId" | ||||
|                 value={newUserState.userId} | ||||
|                 onChange={(e) => setNewUserState({ ...newUserState, userId: e.target.value })} | ||||
|               /> | ||||
|             </div> | ||||
| 
 | ||||
|             <div className="input-group"> | ||||
|               <label htmlFor="username">Username:</label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="username" | ||||
|                 value={newUserState.username} | ||||
|                 onChange={(e) => setNewUserState({ ...newUserState, username: e.target.value })} | ||||
|               /> | ||||
|             </div> | ||||
|             <div className="input-group"> | ||||
|               <label htmlFor="fullName">Full Name:</label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="fullName" | ||||
|                 value={newUserState.fullName} | ||||
|                 onChange={(e) => setNewUserState({ ...newUserState, fullName: e.target.value })} | ||||
|               /> | ||||
|             </div> | ||||
| 
 | ||||
|             <div className="input-group"> | ||||
|               <label htmlFor="email">Email:</label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="email" | ||||
|                 value={newUserState.email} | ||||
|                 onChange={(e) => setNewUserState({ ...newUserState, email: e.target.value })} | ||||
|               /> | ||||
|             </div> | ||||
| 
 | ||||
|              | ||||
| 
 | ||||
|             <div className="input-group"> | ||||
|               <label htmlFor="mobileNumber">Mobile Number:</label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="mobileNumber" | ||||
|                 value={newUserState.mobileNumber} | ||||
|                 onChange={(e) => setNewUserState({ ...newUserState, mobileNumber: e.target.value })} | ||||
|               /> | ||||
|             </div> | ||||
| 
 | ||||
|             <div className="input-group"> | ||||
|               <label htmlFor="userGroup">User Group:</label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="userGroup" | ||||
|                 value={newUserState.userGroup} | ||||
|                 onChange={(e) => setNewUserState({ ...newUserState, userGroup: e.target.value })} | ||||
|               /> | ||||
|             </div> | ||||
| 
 | ||||
|             <button onClick={handleSave}>Save</button> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default Modal; | ||||
| import React, { useState } from 'react'; | ||||
| import './Model.css'; | ||||
| 
 | ||||
| const Modal = ({ setNewUser, newUser, onSave }) => { | ||||
|   const [newUserState, setNewUserState] = useState(newUser); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
| 
 | ||||
|   const handleSave = () => { | ||||
|     const data = {  ...newUserState }; | ||||
|     onSave(data); // Pass the new data to the parent component
 | ||||
|     setIsModalOpen(false); // Close the modal after saving
 | ||||
|   }; | ||||
|    | ||||
| 
 | ||||
|   const handleClose = () => { | ||||
|     setIsModalOpen(false); | ||||
|   }; | ||||
| 
 | ||||
|   const handleOpenModal = () => { | ||||
|     setIsModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       <button onClick={handleOpenModal}>ADD ITEM</button> | ||||
| 
 | ||||
|       {isModalOpen && ( | ||||
|         <div className='modalWrapper'> | ||||
|           <div className='modal'> | ||||
|             <button className="closeBtn" onClick={handleClose}>X</button> | ||||
| 
 | ||||
|             <div className="input-group"> | ||||
|               <label htmlFor="userId">User ID:</label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="userId" | ||||
|                 value={newUserState.userId} | ||||
|                 onChange={(e) => setNewUserState({ ...newUserState, userId: e.target.value })} | ||||
|               /> | ||||
|             </div> | ||||
| 
 | ||||
|             <div className="input-group"> | ||||
|               <label htmlFor="username">Username:</label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="username" | ||||
|                 value={newUserState.username} | ||||
|                 onChange={(e) => setNewUserState({ ...newUserState, username: e.target.value })} | ||||
|               /> | ||||
|             </div> | ||||
|             <div className="input-group"> | ||||
|               <label htmlFor="fullName">Full Name:</label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="fullName" | ||||
|                 value={newUserState.fullName} | ||||
|                 onChange={(e) => setNewUserState({ ...newUserState, fullName: e.target.value })} | ||||
|               /> | ||||
|             </div> | ||||
| 
 | ||||
|             <div className="input-group"> | ||||
|               <label htmlFor="email">Email:</label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="email" | ||||
|                 value={newUserState.email} | ||||
|                 onChange={(e) => setNewUserState({ ...newUserState, email: e.target.value })} | ||||
|               /> | ||||
|             </div> | ||||
| 
 | ||||
|              | ||||
| 
 | ||||
|             <div className="input-group"> | ||||
|               <label htmlFor="mobileNumber">Mobile Number:</label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="mobileNumber" | ||||
|                 value={newUserState.mobileNumber} | ||||
|                 onChange={(e) => setNewUserState({ ...newUserState, mobileNumber: e.target.value })} | ||||
|               /> | ||||
|             </div> | ||||
| 
 | ||||
|             <div className="input-group"> | ||||
|               <label htmlFor="userGroup">User Group:</label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="userGroup" | ||||
|                 value={newUserState.userGroup} | ||||
|                 onChange={(e) => setNewUserState({ ...newUserState, userGroup: e.target.value })} | ||||
|               /> | ||||
|             </div> | ||||
| 
 | ||||
|             <button onClick={handleSave}>Save</button> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default Modal; | ||||
|  | ||||
| @ -1,69 +1,69 @@ | ||||
| 
 | ||||
| 
 | ||||
| .modalWrapper { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     background: rgba(0, 0, 0, 0.5); | ||||
|   } | ||||
|    | ||||
|   .modal { | ||||
|     background: white; | ||||
|     padding: 20px; | ||||
|     border-radius: 8px; | ||||
|     width: 300px; | ||||
|     text-align: left; | ||||
|     position: relative; | ||||
|     box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); | ||||
|   } | ||||
|    | ||||
|   .closeBtn { | ||||
|     position: absolute; | ||||
|     top: 10px; | ||||
|     right: 10px; | ||||
|     font-size: 16px; | ||||
|     cursor: pointer; | ||||
|   } | ||||
|    | ||||
|   label { | ||||
|     display: block; | ||||
|     margin-bottom: 8px; | ||||
|     color: #333; | ||||
|   } | ||||
|    | ||||
|   input { | ||||
|     width: 100%; | ||||
|     padding: 10px; | ||||
|     margin-bottom: 16px; | ||||
|     border: 1px solid #ddd; | ||||
|     border-radius: 4px; | ||||
|   } | ||||
|    | ||||
|   button { | ||||
|     background-color: #4caf50; | ||||
|     color: white; | ||||
|     padding: 12px; | ||||
|     border: none; | ||||
|     border-radius: 4px; | ||||
|     cursor: pointer; | ||||
|      | ||||
|   } | ||||
|    | ||||
|   .savedData { | ||||
|     margin-top: 20px; | ||||
|   } | ||||
|    | ||||
|   .savedData h2 { | ||||
|     font-size: 16px; | ||||
|     margin-bottom: 10px; | ||||
|   } | ||||
|    | ||||
|   .savedData p { | ||||
|     margin: 5px 0; | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
| .modalWrapper { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     background: rgba(0, 0, 0, 0.5); | ||||
|   } | ||||
|    | ||||
|   .modal { | ||||
|     background: white; | ||||
|     padding: 20px; | ||||
|     border-radius: 8px; | ||||
|     width: 300px; | ||||
|     text-align: left; | ||||
|     position: relative; | ||||
|     box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); | ||||
|   } | ||||
|    | ||||
|   .closeBtn { | ||||
|     position: absolute; | ||||
|     top: 10px; | ||||
|     right: 10px; | ||||
|     font-size: 16px; | ||||
|     cursor: pointer; | ||||
|   } | ||||
|    | ||||
|   label { | ||||
|     display: block; | ||||
|     margin-bottom: 8px; | ||||
|     color: #333; | ||||
|   } | ||||
|    | ||||
|   input { | ||||
|     width: 100%; | ||||
|     padding: 10px; | ||||
|     margin-bottom: 16px; | ||||
|     border: 1px solid #ddd; | ||||
|     border-radius: 4px; | ||||
|   } | ||||
|    | ||||
|   button { | ||||
|     background-color: #4caf50; | ||||
|     color: white; | ||||
|     padding: 12px; | ||||
|     border: none; | ||||
|     border-radius: 4px; | ||||
|     cursor: pointer; | ||||
|      | ||||
|   } | ||||
|    | ||||
|   .savedData { | ||||
|     margin-top: 20px; | ||||
|   } | ||||
|    | ||||
|   .savedData h2 { | ||||
|     font-size: 16px; | ||||
|     margin-bottom: 10px; | ||||
|   } | ||||
|    | ||||
|   .savedData p { | ||||
|     margin: 5px 0; | ||||
|   } | ||||
|    | ||||
| @ -1,71 +1,71 @@ | ||||
| /* Report.css */ | ||||
| 
 | ||||
| .app { | ||||
|   font-family: Arial, sans-serif; | ||||
|   margin: 20px auto; /* Adjust margin to create space between cards and navbar */ | ||||
|   padding: 0 20px; | ||||
|   max-width: 800px; | ||||
| } | ||||
| 
 | ||||
| h1 { | ||||
|   text-align: center; | ||||
|   color: #333; | ||||
| } | ||||
| 
 | ||||
| .card-container { | ||||
|   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 */ | ||||
|   gap: 20px; | ||||
|   max-width: 100%; /* Limit the maximum width of the card container */ | ||||
|   margin: 0 auto; /* Center the card container */ | ||||
| } | ||||
| 
 | ||||
| .card { | ||||
|   background-color: #ffffff; | ||||
|   border: 1px solid #e0e0e0; | ||||
|   border-radius: 10px; | ||||
|   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 */ | ||||
|   transition: transform 0.3s ease-in-out; | ||||
|   width: 100%; /* Make cards take up full width of their container */ | ||||
|   height: auto; /* Allow cards to expand vertically based on content */ | ||||
| } | ||||
| 
 | ||||
| .card:hover { | ||||
|   transform: translateY(-5px); | ||||
| } | ||||
| 
 | ||||
| .card h2 { | ||||
|   margin-top: 0; | ||||
|   color: #333; | ||||
|   font-size: 20px; /* Increase font size of card headings */ | ||||
| } | ||||
| 
 | ||||
| .card p { | ||||
|   margin: 10px 0; /* Increase margin for better spacing */ | ||||
|   color: #666; | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 1400px) { | ||||
|   .card-container { | ||||
|     grid-template-columns: minmax(300px, 1fr) minmax(300px, 1fr) repeat(auto-fill, minmax(250px, 1fr)); /* Adjust columns for smaller screens */ | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 1100px) { | ||||
|   .card-container { | ||||
|     grid-template-columns: minmax(250px, 1fr) repeat(auto-fill, minmax(200px, 1fr)); /* Further adjust columns for even smaller screens */ | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 900px) { | ||||
|   .card-container { | ||||
|     grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* Adjust columns for smaller screens */ | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 600px) { | ||||
|   .card-container { | ||||
|     grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); /* Adjust columns for smaller screens */ | ||||
|   } | ||||
| } | ||||
| /* Report.css */ | ||||
| 
 | ||||
| .app { | ||||
|   font-family: Arial, sans-serif; | ||||
|   margin: 20px auto; /* Adjust margin to create space between cards and navbar */ | ||||
|   padding: 0 20px; | ||||
|   max-width: 800px; | ||||
| } | ||||
| 
 | ||||
| h1 { | ||||
|   text-align: center; | ||||
|   color: #333; | ||||
| } | ||||
| 
 | ||||
| .card-container { | ||||
|   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 */ | ||||
|   gap: 20px; | ||||
|   max-width: 100%; /* Limit the maximum width of the card container */ | ||||
|   margin: 0 auto; /* Center the card container */ | ||||
| } | ||||
| 
 | ||||
| .card { | ||||
|   background-color: #ffffff; | ||||
|   border: 1px solid #e0e0e0; | ||||
|   border-radius: 10px; | ||||
|   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 */ | ||||
|   transition: transform 0.3s ease-in-out; | ||||
|   width: 100%; /* Make cards take up full width of their container */ | ||||
|   height: auto; /* Allow cards to expand vertically based on content */ | ||||
| } | ||||
| 
 | ||||
| .card:hover { | ||||
|   transform: translateY(-5px); | ||||
| } | ||||
| 
 | ||||
| .card h2 { | ||||
|   margin-top: 0; | ||||
|   color: #333; | ||||
|   font-size: 20px; /* Increase font size of card headings */ | ||||
| } | ||||
| 
 | ||||
| .card p { | ||||
|   margin: 10px 0; /* Increase margin for better spacing */ | ||||
|   color: #666; | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 1400px) { | ||||
|   .card-container { | ||||
|     grid-template-columns: minmax(300px, 1fr) minmax(300px, 1fr) repeat(auto-fill, minmax(250px, 1fr)); /* Adjust columns for smaller screens */ | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 1100px) { | ||||
|   .card-container { | ||||
|     grid-template-columns: minmax(250px, 1fr) repeat(auto-fill, minmax(200px, 1fr)); /* Further adjust columns for even smaller screens */ | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 900px) { | ||||
|   .card-container { | ||||
|     grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* Adjust columns for smaller screens */ | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 600px) { | ||||
|   .card-container { | ||||
|     grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); /* Adjust columns for smaller screens */ | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,74 +1,80 @@ | ||||
| import React, { useState, useEffect } from "react"; | ||||
| 
 | ||||
| const Card = ({ report }) => { | ||||
|   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"> | ||||
|       <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"> | ||||
|         Active: {report.active ? "Yes" : "No"} | ||||
|       </p> | ||||
|       <p className="text-gray-600">Is SQL: {report.isSql ? "Yes" : "No"}</p> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| // Define the API base URL using the environment variable
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| const Report = () => { | ||||
|   const [reports, setReports] = useState([]); | ||||
|   const [loading, setLoading] = useState(true); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("authToken"); | ||||
| 
 | ||||
|       if (!token) { | ||||
|         console.error("No auth token found. Redirecting to login."); | ||||
|         // You can redirect to the login page here if needed
 | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       try { | ||||
|         const response = await fetch(`${api}/Rpt_builder2/Rpt_builder2`, { | ||||
|           headers: { | ||||
|             Authorization: `Bearer ${token}`, | ||||
|           }, | ||||
|         }); | ||||
| 
 | ||||
|         if (!response.ok) { | ||||
|           throw new Error("Failed to fetch data"); | ||||
|         } | ||||
| 
 | ||||
|         const data = await response.json(); | ||||
|         setReports(data); | ||||
|         setLoading(false); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|         setLoading(false); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   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> | ||||
|       </div> | ||||
|       {loading ? ( | ||||
|         <p className="text-gray-700">Loading...</p> | ||||
|       ) : ( | ||||
|         <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} /> | ||||
|           ))} | ||||
|         </div> | ||||
|       )} | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default Report; | ||||
| import React, { useState, useEffect } from "react"; | ||||
| 
 | ||||
| const Card = ({ report }) => { | ||||
|   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"> | ||||
|       <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"> | ||||
|         Active: {report.active ? "Yes" : "No"} | ||||
|       </p> | ||||
|       <p className="text-gray-600">Is SQL: {report.isSql ? "Yes" : "No"}</p> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| // Define the API base URL using the environment variable
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| const Report = () => { | ||||
|   const [reports, setReports] = useState([]); | ||||
|   const [loading, setLoading] = useState(true); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("authToken"); | ||||
| 
 | ||||
|       if (!token) { | ||||
|         console.error("No auth token found. Redirecting to login."); | ||||
|         // You can redirect to the login page here if needed
 | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       try { | ||||
|         const response = await fetch(`${api}/Rpt_builder2/Rpt_builder2`, { | ||||
|           headers: { | ||||
|             Authorization: `Bearer ${token}`, | ||||
|           }, | ||||
|         }); | ||||
| 
 | ||||
|         if (response.status === 401) { | ||||
|           console.error("Unauthorized. Redirecting to login."); | ||||
|           // Redirect to the login page here if needed
 | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         if (!response.ok) { | ||||
|           throw new Error("Failed to fetch data"); | ||||
|         } | ||||
| 
 | ||||
|         const data = await response.json(); | ||||
|         setReports(data); | ||||
|         setLoading(false); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|         setLoading(false); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   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> | ||||
|       </div> | ||||
|       {loading ? ( | ||||
|         <p className="text-gray-700">Loading...</p> | ||||
|       ) : ( | ||||
|         <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} /> | ||||
|           ))} | ||||
|         </div> | ||||
|       )} | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default Report; | ||||
|  | ||||
| @ -1,29 +1,29 @@ | ||||
| 
 | ||||
| 
 | ||||
| .card-list { | ||||
|     display: flex; | ||||
|     flex-wrap: wrap; /* Allow cards to wrap to the next line */ | ||||
|     justify-content: center; /* Horizontally center the cards */ | ||||
|   } | ||||
|    | ||||
|   .card { | ||||
|     border: 1px solid black; | ||||
|     padding: 10px; | ||||
|     margin: 10px; /* Adjust margin for better spacing */ | ||||
|     width: calc(33.33% - 20px); /* Adjust card width based on container width */ | ||||
|     max-width: 200px; /* Set maximum card width */ | ||||
|     height: 150px; /* Adjust card height */ | ||||
|   } | ||||
|    | ||||
|   @media (max-width: 768px) { | ||||
|     .card { | ||||
|       width: calc(50% - 20px); /* Two cards per row on smaller screens */ | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   @media (max-width: 480px) { | ||||
|     .card { | ||||
|       width: calc(100% - 20px); /* Single card per row on mobile devices */ | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
| .card-list { | ||||
|     display: flex; | ||||
|     flex-wrap: wrap; /* Allow cards to wrap to the next line */ | ||||
|     justify-content: center; /* Horizontally center the cards */ | ||||
|   } | ||||
|    | ||||
|   .card { | ||||
|     border: 1px solid black; | ||||
|     padding: 10px; | ||||
|     margin: 10px; /* Adjust margin for better spacing */ | ||||
|     width: calc(33.33% - 20px); /* Adjust card width based on container width */ | ||||
|     max-width: 200px; /* Set maximum card width */ | ||||
|     height: 150px; /* Adjust card height */ | ||||
|   } | ||||
|    | ||||
|   @media (max-width: 768px) { | ||||
|     .card { | ||||
|       width: calc(50% - 20px); /* Two cards per row on smaller screens */ | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   @media (max-width: 480px) { | ||||
|     .card { | ||||
|       width: calc(100% - 20px); /* Single card per row on mobile devices */ | ||||
|     } | ||||
|   } | ||||
|    | ||||
| @ -1,80 +1,78 @@ | ||||
| import React, { useState } from 'react'; | ||||
| import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||||
| import { faUser, faUsers, faUtensils, faLock, faCogs, faKey } from '@fortawesome/free-solid-svg-icons'; | ||||
| import UserMaintance from './UserMaintance';  | ||||
| import UserGroupMaintance from './UserGroupMaintance/UserGroupMaintance';  | ||||
| import MenuMaintance from './MenuMaintance/MenuMaintance';  | ||||
| import MenuAccessControl from './MenuAccessControl/MenuAccessControl';  | ||||
| import SystemParameters from './SystemParameters/SystemParameters';  | ||||
| import AccessType from './AccessType/AccessType'; | ||||
| import ApiRegistery from './ApiRegistery/ApiRegistery'; | ||||
| import TokenRegistery from './TokenRegistery/TokenRegistery'; | ||||
| import Codeextension from './Codeextension.js'; | ||||
| import DynamicTable from './Dynamictable.js'; | ||||
| 
 | ||||
| const Card = ({ title, content, 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"> | ||||
|     <FontAwesomeIcon icon={icon} className="text-4xl text-gray-800 mb-4" /> | ||||
|     <h3 className="text-lg font-semibold">{title}</h3> | ||||
|     <p className="text-gray-600">{content}</p> | ||||
|   </div> | ||||
| ); | ||||
| 
 | ||||
| const CardList = () => { | ||||
|   const [showUserMaintance, setShowUserMaintance] = useState(false); | ||||
|   const [showUserGroupMaintance, setShowUserGroupMaintance] = useState(false); | ||||
|   const [showMenuMaintance, setShowMenuMaintance] = useState(false); | ||||
|   const [showMenuAccessControl, setShowMenuAccessControl] = useState(false); | ||||
|   const [showSystemParameters, setShowSystemParameters] = useState(false); | ||||
|   const [showAccessType, setShowAccessType] = useState(false); | ||||
|   const [showApiRegistery, setShowApiRegistery] = useState(false); | ||||
|   const [showTokenRegistery, setShowTokenRegistery] = useState(false); | ||||
|   const [showCodeExtension, setShowCodeExtension] = useState(false); | ||||
|   const [showDynamicTable, setShowDynamicTable] = useState(false); | ||||
| 
 | ||||
|   const handleCardClick = (menuItemDesc) => { | ||||
|     setShowUserMaintance(menuItemDesc === 'User Maintance'); | ||||
|     setShowUserGroupMaintance(menuItemDesc === 'User Group Maintance'); | ||||
|     setShowMenuMaintance(menuItemDesc === 'Menu Maintance'); | ||||
|     setShowMenuAccessControl(menuItemDesc === 'Menu Access Control'); | ||||
|     setShowSystemParameters(menuItemDesc === 'System Parameters'); | ||||
|     setShowAccessType(menuItemDesc === 'Access Type'); | ||||
|     setShowApiRegistery(menuItemDesc === 'Api Registery'); | ||||
|     setShowTokenRegistery(menuItemDesc === 'Token Registery'); | ||||
|     setShowCodeExtension(menuItemDesc === 'Code Extension'); | ||||
|     setShowDynamicTable(menuItemDesc === 'Dynamic Table'); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       {!showUserMaintance && !showUserGroupMaintance && !showMenuMaintance && !showMenuAccessControl && !showSystemParameters && !showAccessType && !showApiRegistery && !showTokenRegistery && !showCodeExtension && !showDynamicTable && ( | ||||
|         <div className="min-h-screen flex items-center justify-center bg-gray-100 p-4"> | ||||
|           <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 Maintance" content="Manage users" icon={faUser} onClick={() => handleCardClick('User Maintance')} /> | ||||
|             <Card title="User Group Maintance" content="Manage user groups" icon={faUsers} onClick={() => handleCardClick('User Group Maintance')} /> | ||||
|             <Card title="Menu Maintance" content="Manage menus" icon={faUtensils} onClick={() => handleCardClick('Menu Maintance')} /> | ||||
|             <Card title="Menu Access Control" content="Control menu access" icon={faLock} onClick={() => handleCardClick('Menu Access Control')} /> | ||||
|             <Card title="System Parameters" content="Configure system parameters" icon={faCogs} onClick={() => handleCardClick('System Parameters')} /> | ||||
|             <Card title="Access Type" content="Manage access types" icon={faKey} onClick={() => handleCardClick('Access Type')} /> | ||||
|             <Card title="Api Registery" content="Manage APIs" icon={faUser} onClick={() => handleCardClick('Api Registery')} /> | ||||
|             <Card title="Token Registery" content="Manage tokens" icon={faKey} onClick={() => handleCardClick('Token Registery')} /> | ||||
|             <Card title="Code Extension" content="Extend code functionalities" icon={faLock} onClick={() => handleCardClick('Code Extension')} /> | ||||
|             <Card title="Dynamic Table" content="Dynamic data tables" icon={faKey} onClick={() => handleCardClick('Dynamic Table')} /> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|       {showUserMaintance && <UserMaintance />} | ||||
|       {showUserGroupMaintance && <UserGroupMaintance />} | ||||
|       {showMenuMaintance && <MenuMaintance />} | ||||
|       {showMenuAccessControl && <MenuAccessControl />} | ||||
|       {showSystemParameters && <SystemParameters />} | ||||
|       {showAccessType && <AccessType />} | ||||
|       {showApiRegistery && <ApiRegistery />} | ||||
|       {showTokenRegistery && <TokenRegistery />} | ||||
|       {showCodeExtension && <Codeextension />} | ||||
|       {showDynamicTable && <DynamicTable />} | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default CardList; | ||||
| import React, { useState } from 'react'; | ||||
| import { FaUser, FaUsers, FaUtensils, FaLock, FaCogs, FaKey } from 'react-icons/fa'; | ||||
| import UserMaintance from './UserMaintance';  | ||||
| import UserGroupMaintance from './UserGroupMaintance/UserGroupMaintance';  | ||||
| import MenuMaintance from './MenuMaintance/MenuMaintance';  | ||||
| import MenuAccessControl from './MenuAccessControl/MenuAccessControl';  | ||||
| import SystemParameters from './SystemParameters/SystemParameters';  | ||||
| import ApiRegistery from './ApiRegistery/ApiRegistery'; | ||||
| import TokenRegistery from './TokenRegistery/TokenRegistery'; | ||||
| 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"> | ||||
|     <Icon className="text-4xl text-gray-800 mb-4" /> | ||||
|     <h3 className="text-lg font-semibold">{title}</h3> | ||||
|     <p className="text-gray-600">{content}</p> | ||||
|   </div> | ||||
| ); | ||||
| 
 | ||||
| const CardList = () => { | ||||
|   const [showUserMaintance, setShowUserMaintance] = useState(false); | ||||
|   const [showUserGroupMaintance, setShowUserGroupMaintance] = useState(false); | ||||
|   const [showMenuMaintance, setShowMenuMaintance] = useState(false); | ||||
|   const [showMenuAccessControl, setShowMenuAccessControl] = useState(false); | ||||
|   const [showSystemParameters, setShowSystemParameters] = useState(false); | ||||
|   // const [showAccessType, setShowAccessType] = useState(false);
 | ||||
|   const [showApiRegistery, setShowApiRegistery] = useState(false); | ||||
|   const [showTokenRegistery, setShowTokenRegistery] = useState(false); | ||||
|   const [showCodeExtension, setShowCodeExtension] = useState(false); | ||||
|   const [showDynamicTable, setShowDynamicTable] = useState(false); | ||||
| 
 | ||||
|   const handleCardClick = (menuItemDesc) => { | ||||
|     setShowUserMaintance(menuItemDesc === 'User Maintance'); | ||||
|     setShowUserGroupMaintance(menuItemDesc === 'User Group Maintance'); | ||||
|     setShowMenuMaintance(menuItemDesc === 'Menu Maintance'); | ||||
|     setShowMenuAccessControl(menuItemDesc === 'Menu Access Control'); | ||||
|     setShowSystemParameters(menuItemDesc === 'System Parameters'); | ||||
|     // setShowAccessType(menuItemDesc === 'Access Type');
 | ||||
|     setShowApiRegistery(menuItemDesc === 'Api Registery'); | ||||
|     setShowTokenRegistery(menuItemDesc === 'Token Registery'); | ||||
|     setShowCodeExtension(menuItemDesc === 'Code Extension'); | ||||
|     setShowDynamicTable(menuItemDesc === 'Dynamic Table'); | ||||
|   }; | ||||
| 
 | ||||
|   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"> | ||||
|           <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 Maintance" content="Manage users" icon={FaUser} onClick={() => handleCardClick('User Maintance')} /> | ||||
|             <Card title="User Group Maintance" content="Manage user groups" icon={FaUsers} onClick={() => handleCardClick('User Group Maintance')} /> | ||||
|             <Card title="Menu Maintance" content="Manage menus" icon={FaUtensils} onClick={() => handleCardClick('Menu Maintance')} /> | ||||
|             <Card title="Menu Access Control" content="Control menu access" icon={FaLock} onClick={() => handleCardClick('Menu Access Control')} /> | ||||
|             <Card title="System Parameters" content="Configure system parameters" icon={FaCogs} onClick={() => handleCardClick('System Parameters')} /> | ||||
|             {/* <Card title="Access Type" content="Manage access types" icon={FaKey} onClick={() => handleCardClick('Access Type')} /> */} | ||||
|             <Card title="Api Registery" content="Manage APIs" icon={FaUser} onClick={() => handleCardClick('Api Registery')} /> | ||||
|             <Card title="Token Registery" content="Manage tokens" icon={FaKey} onClick={() => handleCardClick('Token Registery')} /> | ||||
|             <Card title="Code Extension" content="Extend code functionalities" icon={FaLock} onClick={() => handleCardClick('Code Extension')} /> | ||||
|             <Card title="Dynamic Table" content="Dynamic data tables" icon={FaKey} onClick={() => handleCardClick('Dynamic Table')} /> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|       {showUserMaintance && <UserMaintance />} | ||||
|       {showUserGroupMaintance && <UserGroupMaintance />} | ||||
|       {showMenuMaintance && <MenuMaintance />} | ||||
|       {showMenuAccessControl && <MenuAccessControl />} | ||||
|       {showSystemParameters && <SystemParameters />} | ||||
|       {/* {showAccessType && <AccessType />} */} | ||||
|       {showApiRegistery && <ApiRegistery />} | ||||
|       {showTokenRegistery && <TokenRegistery />} | ||||
|       {showCodeExtension && <Codeextension />} | ||||
|       {showDynamicTable && <DynamicTable />} | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default CardList; | ||||
|  | ||||
| @ -1,128 +1,128 @@ | ||||
| import React, { useState } from "react"; | ||||
| import { Button, Container, Grid, TextField } from "@mui/material"; | ||||
| 
 | ||||
| const SystemParameterForm = () => { | ||||
|   const [formData, setFormData] = useState({ | ||||
|     schedulerTimer: "", | ||||
|     leaseTaxCode: "", | ||||
|     vesselConfirmationProcessLimit: "", | ||||
|     rowToDisplay: "", | ||||
|     linkToDisplay: "", | ||||
|     rowToAdd: "", | ||||
|     lovRowToDisplay: "", | ||||
|     lovLinkToDisplay: "", | ||||
|     oldServerName: "", | ||||
|     oldBase: "", | ||||
|     oldAdminUser: "", | ||||
|     oldServerPort: "", | ||||
|     userDefaultGroup: "", | ||||
|     defaultDepartment: "", | ||||
|     defaultPosition: "", | ||||
|     singleCharge: "", | ||||
|     firstDayOfWeek: "", | ||||
|     hourPerShift: "", | ||||
|     cnBillingFrequency: "", | ||||
|     billingDepartmentCode: "", | ||||
|     basePriceList: "", | ||||
|     nonContainerServiceOrderAutoApprovalDeptCode: "", | ||||
|     ediMAESchedulerOnOff: "", | ||||
|     ediSchedulerOnOff: "", | ||||
|     companyDisplayName: "", | ||||
|   }); | ||||
| 
 | ||||
|   const handleInputChange = (event) => { | ||||
|     const { name, value } = event.target; | ||||
|     setFormData((prevState) => ({ | ||||
|       ...prevState, | ||||
|       [name]: value, | ||||
|     })); | ||||
|   }; | ||||
| 
 | ||||
|   const handleFileChange = (event) => { | ||||
|     setFormData((prevState) => ({ | ||||
|       ...prevState, | ||||
|       logo: event.target.files[0], | ||||
|     })); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSubmit = (event) => { | ||||
|     event.preventDefault(); | ||||
|     alert("Form submitted successfully!"); | ||||
|     console.log("Form Data:", formData); | ||||
|   }; | ||||
| 
 | ||||
|   const handleClear = () => { | ||||
|     setFormData({ | ||||
|       schedulerTimer: "", | ||||
|       leaseTaxCode: "", | ||||
|       vesselConfirmationProcessLimit: "", | ||||
|       rowToDisplay: "", | ||||
|       linkToDisplay: "", | ||||
|       rowToAdd: "", | ||||
|       lovRowToDisplay: "", | ||||
|       lovLinkToDisplay: "", | ||||
|       oldServerName: "", | ||||
|       oldBase: "", | ||||
|       oldAdminUser: "", | ||||
|       oldServerPort: "", | ||||
|       userDefaultGroup: "", | ||||
|       defaultDepartment: "", | ||||
|       defaultPosition: "", | ||||
|       singleCharge: "", | ||||
|       firstDayOfWeek: "", | ||||
|       hourPerShift: "", | ||||
|       cnBillingFrequency: "", | ||||
|       billingDepartmentCode: "", | ||||
|       basePriceList: "", | ||||
|       nonContainerServiceOrderAutoApprovalDeptCode: "", | ||||
|       ediMAESchedulerOnOff: "", | ||||
|       ediSchedulerOnOff: "", | ||||
|       companyDisplayName: "", | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <Container className="mt-5"> | ||||
|       <p className="bg-gray-400 text-center text-white text-3xl m-3 p-2"> | ||||
|         System Parameters | ||||
|       </p> | ||||
|       <form onSubmit={handleSubmit} className="m-5 p-5"> | ||||
|         <Grid container spacing={3}> | ||||
|           {Object.keys(formData).map((key, index) => ( | ||||
|             <Grid item xs={12} sm={6} key={index}> | ||||
|               <TextField | ||||
|                 fullWidth | ||||
|                 label={key | ||||
|                   .split(/(?=[A-Z])/) | ||||
|                   .join(" ") | ||||
|                   .replace(/\b\w/g, (l) => l.toUpperCase())} | ||||
|                 name={key} | ||||
|                 value={formData[key]} | ||||
|                 onChange={handleInputChange} | ||||
|                 variant="outlined" | ||||
|               /> | ||||
|             </Grid> | ||||
|           ))} | ||||
|           <Grid item xs={12}> | ||||
|             <input type="file" onChange={handleFileChange} /> | ||||
|           </Grid> | ||||
|         </Grid> | ||||
|         <div style={{ textAlign: "end", marginTop: 20 }}> | ||||
|           <Button | ||||
|             variant="contained" | ||||
|             color="primary" | ||||
|             type="submit" | ||||
|             style={{ marginRight: 10 }} | ||||
|           > | ||||
|             Save | ||||
|           </Button> | ||||
|           <Button variant="outlined" color="primary" onClick={handleClear}> | ||||
|             Clear | ||||
|           </Button> | ||||
|         </div> | ||||
|       </form> | ||||
|     </Container> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default SystemParameterForm; | ||||
| import React, { useState } from "react"; | ||||
| import { Button, Container, Grid, TextField } from "@mui/material"; | ||||
| 
 | ||||
| const SystemParameterForm = () => { | ||||
|   const [formData, setFormData] = useState({ | ||||
|     schedulerTimer: "", | ||||
|     leaseTaxCode: "", | ||||
|     vesselConfirmationProcessLimit: "", | ||||
|     rowToDisplay: "", | ||||
|     linkToDisplay: "", | ||||
|     rowToAdd: "", | ||||
|     lovRowToDisplay: "", | ||||
|     lovLinkToDisplay: "", | ||||
|     oldServerName: "", | ||||
|     oldBase: "", | ||||
|     oldAdminUser: "", | ||||
|     oldServerPort: "", | ||||
|     userDefaultGroup: "", | ||||
|     defaultDepartment: "", | ||||
|     defaultPosition: "", | ||||
|     singleCharge: "", | ||||
|     firstDayOfWeek: "", | ||||
|     hourPerShift: "", | ||||
|     cnBillingFrequency: "", | ||||
|     billingDepartmentCode: "", | ||||
|     basePriceList: "", | ||||
|     nonContainerServiceOrderAutoApprovalDeptCode: "", | ||||
|     ediMAESchedulerOnOff: "", | ||||
|     ediSchedulerOnOff: "", | ||||
|     companyDisplayName: "", | ||||
|   }); | ||||
| 
 | ||||
|   const handleInputChange = (event) => { | ||||
|     const { name, value } = event.target; | ||||
|     setFormData((prevState) => ({ | ||||
|       ...prevState, | ||||
|       [name]: value, | ||||
|     })); | ||||
|   }; | ||||
| 
 | ||||
|   const handleFileChange = (event) => { | ||||
|     setFormData((prevState) => ({ | ||||
|       ...prevState, | ||||
|       logo: event.target.files[0], | ||||
|     })); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSubmit = (event) => { | ||||
|     event.preventDefault(); | ||||
|     alert("Form submitted successfully!"); | ||||
|     console.log("Form Data:", formData); | ||||
|   }; | ||||
| 
 | ||||
|   const handleClear = () => { | ||||
|     setFormData({ | ||||
|       schedulerTimer: "", | ||||
|       leaseTaxCode: "", | ||||
|       vesselConfirmationProcessLimit: "", | ||||
|       rowToDisplay: "", | ||||
|       linkToDisplay: "", | ||||
|       rowToAdd: "", | ||||
|       lovRowToDisplay: "", | ||||
|       lovLinkToDisplay: "", | ||||
|       oldServerName: "", | ||||
|       oldBase: "", | ||||
|       oldAdminUser: "", | ||||
|       oldServerPort: "", | ||||
|       userDefaultGroup: "", | ||||
|       defaultDepartment: "", | ||||
|       defaultPosition: "", | ||||
|       singleCharge: "", | ||||
|       firstDayOfWeek: "", | ||||
|       hourPerShift: "", | ||||
|       cnBillingFrequency: "", | ||||
|       billingDepartmentCode: "", | ||||
|       basePriceList: "", | ||||
|       nonContainerServiceOrderAutoApprovalDeptCode: "", | ||||
|       ediMAESchedulerOnOff: "", | ||||
|       ediSchedulerOnOff: "", | ||||
|       companyDisplayName: "", | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <Container className="mt-5"> | ||||
|       <p className="bg-gray-400 text-center text-white text-3xl m-3 p-2"> | ||||
|         System Parameters | ||||
|       </p> | ||||
|       <form onSubmit={handleSubmit} className="m-5 p-5"> | ||||
|         <Grid container spacing={3}> | ||||
|           {Object.keys(formData).map((key, index) => ( | ||||
|             <Grid item xs={12} sm={6} key={index}> | ||||
|               <TextField | ||||
|                 fullWidth | ||||
|                 label={key | ||||
|                   .split(/(?=[A-Z])/) | ||||
|                   .join(" ") | ||||
|                   .replace(/\b\w/g, (l) => l.toUpperCase())} | ||||
|                 name={key} | ||||
|                 value={formData[key]} | ||||
|                 onChange={handleInputChange} | ||||
|                 variant="outlined" | ||||
|               /> | ||||
|             </Grid> | ||||
|           ))} | ||||
|           <Grid item xs={12}> | ||||
|             <input type="file" onChange={handleFileChange} /> | ||||
|           </Grid> | ||||
|         </Grid> | ||||
|         <div style={{ textAlign: "end", marginTop: 20 }}> | ||||
|           <Button | ||||
|             variant="contained" | ||||
|             color="primary" | ||||
|             type="submit" | ||||
|             style={{ marginRight: 10 }} | ||||
|           > | ||||
|             Save | ||||
|           </Button> | ||||
|           <Button variant="outlined" color="primary" onClick={handleClear}> | ||||
|             Clear | ||||
|           </Button> | ||||
|         </div> | ||||
|       </form> | ||||
|     </Container> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| 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 { Box, Button } from "@mui/material"; | ||||
| import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; | ||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||
| import { faEllipsisV } from "@fortawesome/free-solid-svg-icons"; | ||||
| 
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| function CustomToolbar({ apiRef, handleModal }) { | ||||
|   const handleGoToPage1 = () => { | ||||
|     if (apiRef.current) { | ||||
|       apiRef.current.setPage(1); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <GridToolbarContainer className="flex flex-wrap justify-between p-2 bg-gray-100 border-b border-gray-200"> | ||||
|       <Button | ||||
|         onClick={handleGoToPage1} | ||||
|         className="bg-blue-500 text-white px-4 py-2 rounded shadow hover:bg-blue-600 m-1" | ||||
|       > | ||||
|         Go to page 1 | ||||
|       </Button> | ||||
|       <Button | ||||
|         onClick={handleModal} | ||||
|         className="bg-green-500 text-white px-4 py-2 rounded shadow hover:bg-green-600 m-1" | ||||
|       > | ||||
|         + | ||||
|       </Button> | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function TokenRegistery() { | ||||
|   const [menuItems, setMenuItems] = useState([]); | ||||
|   const [selectedMenuItem, setSelectedMenuItem] = useState(null); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const apiRef = useRef(null); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("token"); // Get token from local storage
 | ||||
|       try { | ||||
|         const response = await fetch( | ||||
|           `${api}/apiregistery/getall`, | ||||
|           { | ||||
|             headers: { | ||||
|               Authorization: `Bearer ${token}`, | ||||
|             }, | ||||
|           } | ||||
|         ); | ||||
|         const data = await response.json(); | ||||
|         setMenuItems(data); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (menuItemId) => { | ||||
|     setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { | ||||
|       field: "table_id", | ||||
|       headerName: "Table ID", | ||||
|       width: 200, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "token_name", | ||||
|       headerName: "Token Name", | ||||
|       width: 250, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "token", | ||||
|       headerName: "Token", | ||||
|       width: 200, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "actions", | ||||
|       headerName: "Actions", | ||||
|       width: 150, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div className="relative"> | ||||
|           <div | ||||
|             className="cursor-pointer" | ||||
|             onClick={() => handleThreeDotsClick(row.id)} | ||||
|           > | ||||
|             <FontAwesomeIcon icon={faEllipsisV} /> | ||||
|           </div> | ||||
|           {selectedMenuItem === row.id && ( | ||||
|             <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"> | ||||
|                 Edit | ||||
|               </button> | ||||
|               <button className="block px-4 py-2 text-gray-800 hover:bg-gray-200 w-full text-left"> | ||||
|                 Delete | ||||
|               </button> | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ), | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   return ( | ||||
|     <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"> | ||||
|         <p className="text-2xl md:text-3xl text-center text-white bg-gray-400 mb-4 p-3"> | ||||
|           Token Registry | ||||
|         </p> | ||||
|         <div className="bg-white p-2 md:p-4 rounded shadow-md"> | ||||
|           <DataGrid | ||||
|             rows={menuItems} | ||||
|             columns={columns} | ||||
|             components={{ | ||||
|               Toolbar: () => ( | ||||
|                 <CustomToolbar | ||||
|                   apiRef={apiRef} | ||||
|                   handleModal={() => setIsModalOpen(true)} | ||||
|                 /> | ||||
|               ), | ||||
|             }} | ||||
|             pageSize={10} | ||||
|             onGridReady={(gridApi) => { | ||||
|               apiRef.current = gridApi; | ||||
|             }} | ||||
|             className="data-grid" | ||||
|           /> | ||||
|         </div> | ||||
|       </Box> | ||||
|       {/* Add your modals and other components here */} | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default TokenRegistery; | ||||
| import React, { useState, useEffect, useRef } from "react"; | ||||
| import { Box, Button } from "@mui/material"; | ||||
| import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; | ||||
| import { BsThreeDotsVertical } from "react-icons/bs"; // Importing react-icons
 | ||||
| 
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| function CustomToolbar({ apiRef, handleModal }) { | ||||
|   const handleGoToPage1 = () => { | ||||
|     if (apiRef.current) { | ||||
|       apiRef.current.setPage(1); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <GridToolbarContainer className="flex flex-wrap justify-between p-2 bg-gray-100 border-b border-gray-200"> | ||||
|       <Button | ||||
|         onClick={handleGoToPage1} | ||||
|         className="bg-blue-500 text-white px-4 py-2 rounded shadow hover:bg-blue-600 m-1" | ||||
|       > | ||||
|         Go to page 1 | ||||
|       </Button> | ||||
|       <Button | ||||
|         onClick={handleModal} | ||||
|         className="bg-green-500 text-white px-4 py-2 rounded shadow hover:bg-green-600 m-1" | ||||
|       > | ||||
|         + | ||||
|       </Button> | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function TokenRegistry() { | ||||
|   const [menuItems, setMenuItems] = useState([]); | ||||
|   const [selectedMenuItem, setSelectedMenuItem] = useState(null); | ||||
|   const [, setIsModalOpen] = useState(false); | ||||
|   const apiRef = useRef(null); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("token"); // Get token from local storage
 | ||||
|       try { | ||||
|         const response = await fetch( | ||||
|           `${api}/apiregistery/getall`, | ||||
|           { | ||||
|             headers: { | ||||
|               Authorization: `Bearer ${token}`, | ||||
|             }, | ||||
|           } | ||||
|         ); | ||||
|         const data = await response.json(); | ||||
|         setMenuItems(data); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (menuItemId) => { | ||||
|     setSelectedMenuItem(menuItemId === selectedMenuItem ? null : menuItemId); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { | ||||
|       field: "table_id", | ||||
|       headerName: "Table ID", | ||||
|       width: 200, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "token_name", | ||||
|       headerName: "Token Name", | ||||
|       width: 250, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "token", | ||||
|       headerName: "Token", | ||||
|       width: 200, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "actions", | ||||
|       headerName: "Actions", | ||||
|       width: 150, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div className="relative"> | ||||
|           <div | ||||
|             className="cursor-pointer" | ||||
|             onClick={() => handleThreeDotsClick(row.id)} | ||||
|           > | ||||
|             <BsThreeDotsVertical /> {/* Updated icon from react-icons */} | ||||
|           </div> | ||||
|           {selectedMenuItem === row.id && ( | ||||
|             <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"> | ||||
|                 Edit | ||||
|               </button> | ||||
|               <button className="block px-4 py-2 text-gray-800 hover:bg-gray-200 w-full text-left"> | ||||
|                 Delete | ||||
|               </button> | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ), | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   return ( | ||||
|     <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"> | ||||
|         <p className="text-2xl md:text-3xl text-center text-white bg-gray-400 mb-4 p-3"> | ||||
|           Token Registry | ||||
|         </p> | ||||
|         <div className="bg-white p-2 md:p-4 rounded shadow-md"> | ||||
|           <DataGrid | ||||
|             rows={menuItems} | ||||
|             columns={columns} | ||||
|             components={{ | ||||
|               Toolbar: () => ( | ||||
|                 <CustomToolbar | ||||
|                   apiRef={apiRef} | ||||
|                   handleModal={() => setIsModalOpen(true)} | ||||
|                 /> | ||||
|               ), | ||||
|             }} | ||||
|             pageSize={10} | ||||
|             onGridReady={(gridApi) => { | ||||
|               apiRef.current = gridApi; | ||||
|             }} | ||||
|             className="data-grid" | ||||
|           /> | ||||
|         </div> | ||||
|       </Box> | ||||
|       {/* Add your modals and other components here */} | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default TokenRegistry; | ||||
|  | ||||
| @ -1,41 +1,41 @@ | ||||
| /* UpdateModal.css */ | ||||
| 
 | ||||
| .modalWrapper { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     background: rgba(0, 0, 0, 0.5); | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|   } | ||||
|    | ||||
|   .modal { | ||||
|     background: white; | ||||
|     padding: 20px; | ||||
|     border-radius: 8px; | ||||
|     box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); | ||||
|   } | ||||
|    | ||||
|   label { | ||||
|     display: block; | ||||
|     margin-bottom: 5px; | ||||
|   } | ||||
|    | ||||
|   input { | ||||
|     width: 100%; | ||||
|     padding: 8px; | ||||
|     margin-bottom: 10px; | ||||
|   } | ||||
|    | ||||
|   button { | ||||
|     background-color: #4caf50; | ||||
|     color: white; | ||||
|     padding: 10px 15px; | ||||
|     border: none; | ||||
|     border-radius: 4px; | ||||
|     cursor: pointer; | ||||
|   } | ||||
| /* UpdateModal.css */ | ||||
| 
 | ||||
| .modalWrapper { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     background: rgba(0, 0, 0, 0.5); | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|   } | ||||
|    | ||||
|   .modal { | ||||
|     background: white; | ||||
|     padding: 20px; | ||||
|     border-radius: 8px; | ||||
|     box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); | ||||
|   } | ||||
|    | ||||
|   label { | ||||
|     display: block; | ||||
|     margin-bottom: 5px; | ||||
|   } | ||||
|    | ||||
|   input { | ||||
|     width: 100%; | ||||
|     padding: 8px; | ||||
|     margin-bottom: 10px; | ||||
|   } | ||||
|    | ||||
|   button { | ||||
|     background-color: #4caf50; | ||||
|     color: white; | ||||
|     padding: 10px 15px; | ||||
|     border: none; | ||||
|     border-radius: 4px; | ||||
|     cursor: pointer; | ||||
|   } | ||||
|    | ||||
| @ -1,107 +1,107 @@ | ||||
| import React, { useState, useEffect } from 'react'; | ||||
| 
 | ||||
| const UpdateModal = ({ user, onUpdate, onClose }) => { | ||||
|   const [updatedUser, setUpdatedUser] = useState(() => ({ ...user })); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     console.log('Updated user state:', updatedUser); | ||||
|   }, [updatedUser]); | ||||
| 
 | ||||
|   const handleChange = (field, value) => { | ||||
|     const updatedData = { ...updatedUser, [field]: value }; | ||||
|     setUpdatedUser(updatedData); | ||||
|   }; | ||||
|   const handleSave = () => { | ||||
|     onUpdate(updatedUser); | ||||
|     onClose(); | ||||
|   }; | ||||
|    | ||||
|   const handleUpdate = () => { | ||||
|     console.log('Before update:', updatedUser); | ||||
|     onUpdate(updatedUser); | ||||
| 
 | ||||
|     onClose(); | ||||
|    | ||||
| 
 | ||||
|     // Use a callback function with setUpdatedUser to ensure the state is updated
 | ||||
|     setUpdatedUser((prev) => { | ||||
|       const updatedData = { ...prev }; | ||||
|       console.log('Updated data:', updatedData); | ||||
| 
 | ||||
|       onUpdate(updatedData); // Pass the updatedData to onUpdate
 | ||||
|       onClose(); | ||||
|       return updatedData; // Return the updatedData to setUpdatedUser
 | ||||
|     }); | ||||
| 
 | ||||
|     // Set the updatedUser state directly to ensure the UI reflects the changes
 | ||||
|     setUpdatedUser(updatedUser); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="modalWrapper"> | ||||
|       <div className="modal"> | ||||
|         <button className="closeBtn" onClick={onClose}> | ||||
|           X | ||||
|         </button> | ||||
|         <div>User ID: {user.userId}</div> | ||||
|         <div>Username: {user.username}</div> | ||||
|         <div>Full Name: {user.fullName}</div> | ||||
| 
 | ||||
|         <div>Email: {user.email}</div> | ||||
|          | ||||
|         <div>Mob Number: {user.mobno}</div> | ||||
|         <div>User grp name: {user.usergrpname}</div> | ||||
| 
 | ||||
|         <label htmlFor="updatedUserId">User ID:</label> | ||||
|         <input | ||||
|           id="updatedUserId" | ||||
|           type="text" | ||||
|           value={updatedUser.userId} | ||||
|           onChange={(e) => handleChange('userId', e.target.value)} | ||||
|         /> | ||||
| 
 | ||||
|         <label htmlFor="updatedUsername">Username:</label> | ||||
|         <input | ||||
|           id="updatedUsername" | ||||
|           type="text" | ||||
|           value={updatedUser.username} | ||||
|           onChange={(e) => handleChange('username', e.target.value)} | ||||
|         /> | ||||
| 
 | ||||
|         <label htmlFor="updatedEmail">Email:</label> | ||||
|         <input | ||||
|           id="updatedEmail" | ||||
|           type="text" | ||||
|           value={updatedUser.email} | ||||
|           onChange={(e) => handleChange('email', e.target.value)} | ||||
|         /> | ||||
| 
 | ||||
|         <label htmlFor="updatedFullName">Full Name:</label> | ||||
|         <input | ||||
|           id="updatedFullName" | ||||
|           type="text" | ||||
|           value={updatedUser.fullName} | ||||
|           onChange={(e) => handleChange('fullName', e.target.value)} | ||||
|         /> | ||||
| <label htmlFor="updatedMobno">Mob No:</label> | ||||
|         <input | ||||
|           id="updatedmobno" | ||||
|           type="number" | ||||
|           value={updatedUser.mobno} | ||||
|           onChange={(e) => handleChange('mobno', e.target.value)} | ||||
|         /> | ||||
| <label htmlFor="updatedusergrpname">User grp name:</label> | ||||
|         <input | ||||
|           id="updatedusergrpname" | ||||
|           type="text" | ||||
|           value={updatedUser.usergrpname} | ||||
|           onChange={(e) => handleChange('usergrpname', e.target.value)} | ||||
|         /> | ||||
| 
 | ||||
|         <button onClick={handleSave}>SAVE</button> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default UpdateModal; | ||||
| import React, { useState, useEffect } from 'react'; | ||||
| 
 | ||||
| const UpdateModal = ({ user, onUpdate, onClose }) => { | ||||
|   const [updatedUser, setUpdatedUser] = useState(() => ({ ...user })); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     console.log('Updated user state:', updatedUser); | ||||
|   }, [updatedUser]); | ||||
| 
 | ||||
|   const handleChange = (field, value) => { | ||||
|     const updatedData = { ...updatedUser, [field]: value }; | ||||
|     setUpdatedUser(updatedData); | ||||
|   }; | ||||
|   const handleSave = () => { | ||||
|     onUpdate(updatedUser); | ||||
|     onClose(); | ||||
|   }; | ||||
|    | ||||
|   // const handleUpdate = () => {
 | ||||
|   //   console.log('Before update:', updatedUser);
 | ||||
|   //   onUpdate(updatedUser);
 | ||||
| 
 | ||||
|   //   onClose();
 | ||||
|    | ||||
| 
 | ||||
|   //   // Use a callback function with setUpdatedUser to ensure the state is updated
 | ||||
|   //   setUpdatedUser((prev) => {
 | ||||
|   //     const updatedData = { ...prev };
 | ||||
|   //     console.log('Updated data:', updatedData);
 | ||||
| 
 | ||||
|   //     onUpdate(updatedData); // Pass the updatedData to onUpdate
 | ||||
|   //     onClose();
 | ||||
|   //     return updatedData; // Return the updatedData to setUpdatedUser
 | ||||
|   //   });
 | ||||
| 
 | ||||
|   //   // Set the updatedUser state directly to ensure the UI reflects the changes
 | ||||
|   //   setUpdatedUser(updatedUser);
 | ||||
|   // };
 | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="modalWrapper"> | ||||
|       <div className="modal"> | ||||
|         <button className="closeBtn" onClick={onClose}> | ||||
|           X | ||||
|         </button> | ||||
|         <div>User ID: {user.userId}</div> | ||||
|         <div>Username: {user.username}</div> | ||||
|         <div>Full Name: {user.fullName}</div> | ||||
| 
 | ||||
|         <div>Email: {user.email}</div> | ||||
|          | ||||
|         <div>Mob Number: {user.mobno}</div> | ||||
|         <div>User grp name: {user.usergrpname}</div> | ||||
| 
 | ||||
|         <label htmlFor="updatedUserId">User ID:</label> | ||||
|         <input | ||||
|           id="updatedUserId" | ||||
|           type="text" | ||||
|           value={updatedUser.userId} | ||||
|           onChange={(e) => handleChange('userId', e.target.value)} | ||||
|         /> | ||||
| 
 | ||||
|         <label htmlFor="updatedUsername">Username:</label> | ||||
|         <input | ||||
|           id="updatedUsername" | ||||
|           type="text" | ||||
|           value={updatedUser.username} | ||||
|           onChange={(e) => handleChange('username', e.target.value)} | ||||
|         /> | ||||
| 
 | ||||
|         <label htmlFor="updatedEmail">Email:</label> | ||||
|         <input | ||||
|           id="updatedEmail" | ||||
|           type="text" | ||||
|           value={updatedUser.email} | ||||
|           onChange={(e) => handleChange('email', e.target.value)} | ||||
|         /> | ||||
| 
 | ||||
|         <label htmlFor="updatedFullName">Full Name:</label> | ||||
|         <input | ||||
|           id="updatedFullName" | ||||
|           type="text" | ||||
|           value={updatedUser.fullName} | ||||
|           onChange={(e) => handleChange('fullName', e.target.value)} | ||||
|         /> | ||||
| <label htmlFor="updatedMobno">Mob No:</label> | ||||
|         <input | ||||
|           id="updatedmobno" | ||||
|           type="number" | ||||
|           value={updatedUser.mobno} | ||||
|           onChange={(e) => handleChange('mobno', e.target.value)} | ||||
|         /> | ||||
| <label htmlFor="updatedusergrpname">User grp name:</label> | ||||
|         <input | ||||
|           id="updatedusergrpname" | ||||
|           type="text" | ||||
|           value={updatedUser.usergrpname} | ||||
|           onChange={(e) => handleChange('usergrpname', e.target.value)} | ||||
|         /> | ||||
| 
 | ||||
|         <button onClick={handleSave}>SAVE</button> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default UpdateModal; | ||||
|  | ||||
| @ -1,69 +1,69 @@ | ||||
| .modalWrapper { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     background: rgba(0, 0, 0, 0.5); | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|   } | ||||
|    | ||||
|   .modal { | ||||
|     background: #fff; | ||||
|     padding: 20px; | ||||
|     border-radius: 8px; | ||||
|     box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); | ||||
|     width: 300px; | ||||
|     max-width: 100%; | ||||
|   } | ||||
|    | ||||
|   .closeBtn { | ||||
|     background: none; | ||||
|     border: none; | ||||
|     font-size: 18px; | ||||
|     color: #333; | ||||
|     cursor: pointer; | ||||
|     position: absolute; | ||||
|     top: 10px; | ||||
|     right: 10px; | ||||
|   } | ||||
|    | ||||
|   label { | ||||
|     display: block; | ||||
|     margin-bottom: 5px; | ||||
|     font-weight: bold; | ||||
|   } | ||||
|    | ||||
|   input { | ||||
|     width: 100%; | ||||
|     padding: 8px; | ||||
|     margin-bottom: 10px; | ||||
|     border: 1px solid #ccc; | ||||
|     border-radius: 4px; | ||||
|     box-sizing: border-box; | ||||
|   } | ||||
|    | ||||
|   button { | ||||
|     background-color: #4caf50; | ||||
|     color: white; | ||||
|     padding: 10px 15px; | ||||
|     border: none; | ||||
|     border-radius: 4px; | ||||
|     cursor: pointer; | ||||
|     margin-right: 10px; | ||||
|   } | ||||
|    | ||||
|   button:hover { | ||||
|     background-color: #45a049; | ||||
|   } | ||||
|    | ||||
|   button:last-child { | ||||
|     background-color: #36bbf4; | ||||
|   } | ||||
|    | ||||
|   button:last-child:hover { | ||||
|     background-color: #2f8cd3; | ||||
|   } | ||||
| .modalWrapper { | ||||
|     position: fixed; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     background: rgba(0, 0, 0, 0.5); | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|   } | ||||
|    | ||||
|   .modal { | ||||
|     background: #fff; | ||||
|     padding: 20px; | ||||
|     border-radius: 8px; | ||||
|     box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); | ||||
|     width: 300px; | ||||
|     max-width: 100%; | ||||
|   } | ||||
|    | ||||
|   .closeBtn { | ||||
|     background: none; | ||||
|     border: none; | ||||
|     font-size: 18px; | ||||
|     color: #333; | ||||
|     cursor: pointer; | ||||
|     position: absolute; | ||||
|     top: 10px; | ||||
|     right: 10px; | ||||
|   } | ||||
|    | ||||
|   label { | ||||
|     display: block; | ||||
|     margin-bottom: 5px; | ||||
|     font-weight: bold; | ||||
|   } | ||||
|    | ||||
|   input { | ||||
|     width: 100%; | ||||
|     padding: 8px; | ||||
|     margin-bottom: 10px; | ||||
|     border: 1px solid #ccc; | ||||
|     border-radius: 4px; | ||||
|     box-sizing: border-box; | ||||
|   } | ||||
|    | ||||
|   button { | ||||
|     background-color: #4caf50; | ||||
|     color: white; | ||||
|     padding: 10px 15px; | ||||
|     border: none; | ||||
|     border-radius: 4px; | ||||
|     cursor: pointer; | ||||
|     margin-right: 10px; | ||||
|   } | ||||
|    | ||||
|   button:hover { | ||||
|     background-color: #45a049; | ||||
|   } | ||||
|    | ||||
|   button:last-child { | ||||
|     background-color: #36bbf4; | ||||
|   } | ||||
|    | ||||
|   button:last-child:hover { | ||||
|     background-color: #2f8cd3; | ||||
|   } | ||||
|    | ||||
| @ -1,146 +1,146 @@ | ||||
| // AddUserGroupModal.js
 | ||||
| import React, { useState } from 'react'; | ||||
| import './Modelitem.css'; | ||||
| 
 | ||||
| const AddUserGroupModal = ({ showModal, handleCloseModal, onSave }) => { | ||||
|   const [newUserData, setNewUserData] = useState({ | ||||
|     groupName: '', | ||||
|     groupDesc: '', | ||||
|     createBy: '', | ||||
|     createDate: '', | ||||
|     updateDate: '', | ||||
|     updateBy: '', | ||||
|     status: '', | ||||
|     groupLevel: '', | ||||
|     createDateFormatted: '', | ||||
|     updateDateFormatted: '', | ||||
|     // Add more fields as needed
 | ||||
|   }); | ||||
| 
 | ||||
|    | ||||
|   const handleSave = () => { | ||||
|     // Format date fields before saving
 | ||||
|     const formattedData = { | ||||
|       ...newUserData, | ||||
|       createDate: new Date(newUserData.createDate).toISOString(), | ||||
|       updateDate: new Date(newUserData.updateDate).toISOString(), | ||||
|     }; | ||||
|    | ||||
|     onSave(formattedData); // Pass the new data to the parent component
 | ||||
|     handleCloseModal(); // Close the modal after saving
 | ||||
|   }; | ||||
|    | ||||
|   const handleCancel = () => { | ||||
|     setNewUserData({ | ||||
|       groupName: '', | ||||
|       groupDesc: '', | ||||
|       createBy: '', | ||||
|       createDate: '', | ||||
|       updateDate: '', | ||||
|       updateBy: '', | ||||
|       status: '', | ||||
|       groupLevel: '', | ||||
|       createDateFormatted: '', | ||||
|       updateDateFormatted: '', | ||||
|       // Reset other fields as needed
 | ||||
|     }); | ||||
|     handleCloseModal(); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       {showModal && ( | ||||
|         <div className='modalWrapper'> | ||||
|           <div className='modal'> | ||||
|             <button className="closeBtn" onClick={handleCancel}>X</button> | ||||
| 
 | ||||
|             <label htmlFor="groupName">Group Name:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="groupName" | ||||
|               value={newUserData.groupName} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, groupName: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="groupDesc">Group Description:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="groupDesc" | ||||
|               value={newUserData.groupDesc} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, groupDesc: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="createBy">Create By:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="createBy" | ||||
|               value={newUserData.createBy} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, createBy: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="createDate">Create Date:</label> | ||||
|             <input | ||||
|               type="date" | ||||
|               id="createDate" | ||||
|               value={newUserData.createDate} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, createDate: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="updateDate">Update Date:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="updateDate" | ||||
|               value={newUserData.updateDate} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, updateDate: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="updateBy">Update By:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="updateBy" | ||||
|               value={newUserData.updateBy} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, updateBy: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="status">Status:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="status" | ||||
|               value={newUserData.status} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, status: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="groupLevel">Group Level:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="groupLevel" | ||||
|               value={newUserData.groupLevel} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, groupLevel: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="createDateFormatted">Create Date Formatted:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="createDateFormatted" | ||||
|               value={newUserData.createDateFormatted} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, createDateFormatted: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="updateDateFormatted">Update Date Formatted:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="updateDateFormatted" | ||||
|               value={newUserData.updateDateFormatted} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, updateDateFormatted: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <button onClick={handleSave}>Save</button> | ||||
|             <button onClick={handleCancel}>Cancel</button> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default AddUserGroupModal; | ||||
| // AddUserGroupModal.js
 | ||||
| import React, { useState } from 'react'; | ||||
| import './Modelitem.css'; | ||||
| 
 | ||||
| const AddUserGroupModal = ({ showModal, handleCloseModal, onSave }) => { | ||||
|   const [newUserData, setNewUserData] = useState({ | ||||
|     groupName: '', | ||||
|     groupDesc: '', | ||||
|     createBy: '', | ||||
|     createDate: '', | ||||
|     updateDate: '', | ||||
|     updateBy: '', | ||||
|     status: '', | ||||
|     groupLevel: '', | ||||
|     createDateFormatted: '', | ||||
|     updateDateFormatted: '', | ||||
|     // Add more fields as needed
 | ||||
|   }); | ||||
| 
 | ||||
|    | ||||
|   const handleSave = () => { | ||||
|     // Format date fields before saving
 | ||||
|     const formattedData = { | ||||
|       ...newUserData, | ||||
|       createDate: new Date(newUserData.createDate).toISOString(), | ||||
|       updateDate: new Date(newUserData.updateDate).toISOString(), | ||||
|     }; | ||||
|    | ||||
|     onSave(formattedData); // Pass the new data to the parent component
 | ||||
|     handleCloseModal(); // Close the modal after saving
 | ||||
|   }; | ||||
|    | ||||
|   const handleCancel = () => { | ||||
|     setNewUserData({ | ||||
|       groupName: '', | ||||
|       groupDesc: '', | ||||
|       createBy: '', | ||||
|       createDate: '', | ||||
|       updateDate: '', | ||||
|       updateBy: '', | ||||
|       status: '', | ||||
|       groupLevel: '', | ||||
|       createDateFormatted: '', | ||||
|       updateDateFormatted: '', | ||||
|       // Reset other fields as needed
 | ||||
|     }); | ||||
|     handleCloseModal(); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       {showModal && ( | ||||
|         <div className='modalWrapper'> | ||||
|           <div className='modal'> | ||||
|             <button className="closeBtn" onClick={handleCancel}>X</button> | ||||
| 
 | ||||
|             <label htmlFor="groupName">Group Name:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="groupName" | ||||
|               value={newUserData.groupName} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, groupName: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="groupDesc">Group Description:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="groupDesc" | ||||
|               value={newUserData.groupDesc} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, groupDesc: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="createBy">Create By:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="createBy" | ||||
|               value={newUserData.createBy} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, createBy: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="createDate">Create Date:</label> | ||||
|             <input | ||||
|               type="date" | ||||
|               id="createDate" | ||||
|               value={newUserData.createDate} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, createDate: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="updateDate">Update Date:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="updateDate" | ||||
|               value={newUserData.updateDate} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, updateDate: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="updateBy">Update By:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="updateBy" | ||||
|               value={newUserData.updateBy} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, updateBy: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="status">Status:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="status" | ||||
|               value={newUserData.status} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, status: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="groupLevel">Group Level:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="groupLevel" | ||||
|               value={newUserData.groupLevel} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, groupLevel: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="createDateFormatted">Create Date Formatted:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="createDateFormatted" | ||||
|               value={newUserData.createDateFormatted} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, createDateFormatted: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <label htmlFor="updateDateFormatted">Update Date Formatted:</label> | ||||
|             <input | ||||
|               type="text" | ||||
|               id="updateDateFormatted" | ||||
|               value={newUserData.updateDateFormatted} | ||||
|               onChange={(e) => setNewUserData((prevData) => ({ ...prevData, updateDateFormatted: e.target.value }))} | ||||
|             /> | ||||
| 
 | ||||
|             <button onClick={handleSave}>Save</button> | ||||
|             <button onClick={handleCancel}>Cancel</button> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| 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'); | ||||
| .custom-header, .custom-cell { | ||||
|   font-family: 'PT Serif", serif ';  | ||||
|    | ||||
|   font-style: normal; | ||||
|   font-weight: bold; | ||||
| } | ||||
| @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 { | ||||
|   font-family: 'PT Serif", serif ';  | ||||
|    | ||||
|   font-style: normal; | ||||
|   font-weight: bold; | ||||
| } | ||||
|  | ||||
| @ -1,224 +1,221 @@ | ||||
| import React, { useState, useEffect, useRef } from "react"; | ||||
| import { Box, Button } from "@mui/material"; | ||||
| import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; | ||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||
| import { faEllipsisV } from "@fortawesome/free-solid-svg-icons"; | ||||
| import "./UserGroupMaintance.css"; | ||||
| import { Token } from "@mui/icons-material"; | ||||
| 
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) { | ||||
|   const handleGoToPage1 = () => { | ||||
|     if (apiRef.current) { | ||||
|       apiRef.current.setPage(1); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <GridToolbarContainer> | ||||
|       <Button onClick={handleGoToPage1}>Go to page 1</Button> | ||||
|       <Button onClick={handleModal}>+</Button> | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function UserMaintance() { | ||||
|   const [userGroups, setUserGroups] = useState([]); | ||||
|   const [selectedUserGroup, setSelectedUserGroup] = useState(null); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const [isUpdateModalOpen, setIsUpdateModalOpen] = useState(false); | ||||
|   const apiRef = useRef(null); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("token"); | ||||
|       try { | ||||
|         const response = await fetch(`${api}/api/getAllUsrGrp`, { | ||||
|           headers: { authorization: `bearer ${token}` }, | ||||
|         }); | ||||
|         const data = await response.json(); | ||||
|         const userGroupsWithIds = data.map((group, index) => ({ | ||||
|           ...group, | ||||
|           id: index + 1, | ||||
|         })); | ||||
|         setUserGroups(userGroupsWithIds); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (usrGrp) => { | ||||
|     setSelectedUserGroup(usrGrp === selectedUserGroup ? null : usrGrp); | ||||
|   }; | ||||
| 
 | ||||
|   const handleDelete = async (usrGrp) => { | ||||
|     try { | ||||
|       const response = await fetch(`${api}/api/delete_usrgrp/${usrGrp}`, { | ||||
|         method: "DELETE", | ||||
|       }); | ||||
|       if (response.ok) { | ||||
|         setUserGroups(userGroups.filter((group) => group.usrGrp !== usrGrp)); | ||||
|         console.log("User group deleted successfully:", usrGrp); | ||||
|       } else { | ||||
|         console.error("Failed to delete user group:", response.statusText); | ||||
|       } | ||||
|     } catch (error) { | ||||
|       console.error("Error deleting user group:", error); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleModal = () => { | ||||
|     setIsModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { | ||||
|       field: "usrGrp", | ||||
|       headerName: "User Group ID", | ||||
|       width: 150, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "groupName", | ||||
|       headerName: "Group Name", | ||||
|       width: 150, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "groupDesc", | ||||
|       headerName: "Group Description", | ||||
|       width: 150, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "createby", | ||||
|       headerName: "Create By", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "createdate", | ||||
|       headerName: "Create Date", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "updatedate", | ||||
|       headerName: "Update Date", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "updateby", | ||||
|       headerName: "Update By", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "status", | ||||
|       headerName: "Status", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "grouplevel", | ||||
|       headerName: "Group Level", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "createdateformated", | ||||
|       headerName: "Create Date Formated", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "updatedateformated", | ||||
|       headerName: "Update Date Formated", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
| 
 | ||||
|     // Add other columns as needed
 | ||||
|     { | ||||
|       field: "actions", | ||||
|       headerName: "Actions", | ||||
|       width: 150, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div> | ||||
|           <div | ||||
|             className="three-dots" | ||||
|             onClick={() => handleThreeDotsClick(row.usrGrp)} | ||||
|           > | ||||
|             <FontAwesomeIcon icon={faEllipsisV} /> | ||||
|           </div> | ||||
|           {selectedUserGroup === row.usrGrp && ( | ||||
|             <div className="popover"> | ||||
|               <button onClick={() => handleDelete(row.usrGrp)}>Delete</button> | ||||
|               {/* You can include other actions here */} | ||||
|             </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"> | ||||
|         User Group Maintenance | ||||
|       </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%" }} | ||||
|       > | ||||
|         <DataGrid | ||||
|           rows={userGroups} | ||||
|           columns={columns} | ||||
|           components={{ | ||||
|             Toolbar: () => ( | ||||
|               <CustomToolbar | ||||
|                 apiRef={apiRef} | ||||
|                 handleThreeDotsClick={handleThreeDotsClick} | ||||
|                 handleModal={handleModal} | ||||
|               /> | ||||
|             ), | ||||
|           }} | ||||
|           pageSize={10} | ||||
|           onGridReady={(gridApi) => { | ||||
|             apiRef.current = gridApi; | ||||
|           }} | ||||
|           className="bg-gray-400" | ||||
|         /> | ||||
|       </Box> | ||||
|       {/* Your modals and other components */} | ||||
|       {isModalOpen && ( | ||||
|         <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"> | ||||
|             <h2 className="text-xl font-bold mb-4">Modal Title</h2> | ||||
|             {/* Modal content here */} | ||||
|             <Button onClick={() => setIsModalOpen(false)}>Close</Button> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default UserMaintance; | ||||
| import React, { useState, useEffect, useRef } from "react"; | ||||
| import { Box, Button } from "@mui/material"; | ||||
| import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; | ||||
| import { BsThreeDotsVertical } from "react-icons/bs"; | ||||
| import "./UserGroupMaintance.css"; | ||||
|  // eslint-disable-next-line
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| function CustomToolbar({ apiRef, handleModal }) { | ||||
|   const handleGoToPage1 = () => { | ||||
|     if (apiRef.current) { | ||||
|       apiRef.current.setPage(1); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <GridToolbarContainer> | ||||
|       <Button onClick={handleGoToPage1}>Go to page 1</Button> | ||||
|       <Button onClick={handleModal}>+</Button> | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function UserMaintance() { | ||||
|   const [userGroups, setUserGroups] = useState([]); | ||||
|   const [selectedUserGroup, setSelectedUserGroup] = useState(null); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const apiRef = useRef(null); | ||||
|  // eslint-disable-next-line
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("token"); | ||||
|       try { | ||||
|         const response = await fetch(`${api}/api/getAllUsrGrp`, { | ||||
|           headers: { authorization: `bearer ${token}` }, | ||||
|         }); | ||||
|         const data = await response.json(); | ||||
|         const userGroupsWithIds = data.map((group, index) => ({ | ||||
|           ...group, | ||||
|           id: index + 1, | ||||
|         })); | ||||
|         setUserGroups(userGroupsWithIds); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (usrGrp) => { | ||||
|     setSelectedUserGroup(usrGrp === selectedUserGroup ? null : usrGrp); | ||||
|   }; | ||||
| 
 | ||||
|   const handleDelete = async (usrGrp) => { | ||||
|     try { | ||||
|       const response = await fetch(`${api}/api/delete_usrgrp/${usrGrp}`, { | ||||
|         method: "DELETE", | ||||
|       }); | ||||
|       if (response.ok) { | ||||
|         setUserGroups(userGroups.filter((group) => group.usrGrp !== usrGrp)); | ||||
|         console.log("User group deleted successfully:", usrGrp); | ||||
|       } else { | ||||
|         console.error("Failed to delete user group:", response.statusText); | ||||
|       } | ||||
|     } catch (error) { | ||||
|       console.error("Error deleting user group:", error); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleModal = () => { | ||||
|     setIsModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { | ||||
|       field: "usrGrp", | ||||
|       headerName: "User Group ID", | ||||
|       width: 150, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "groupName", | ||||
|       headerName: "Group Name", | ||||
|       width: 150, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "groupDesc", | ||||
|       headerName: "Group Description", | ||||
|       width: 150, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "createby", | ||||
|       headerName: "Create By", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "createdate", | ||||
|       headerName: "Create Date", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "updatedate", | ||||
|       headerName: "Update Date", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "updateby", | ||||
|       headerName: "Update By", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "status", | ||||
|       headerName: "Status", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "grouplevel", | ||||
|       headerName: "Group Level", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "createdateformated", | ||||
|       headerName: "Create Date Formated", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
|     { | ||||
|       field: "updatedateformated", | ||||
|       headerName: "Update Date Formated", | ||||
|       width: 100, | ||||
|       headerClassName: "custom-header", | ||||
|       cellClassName: "custom-cell", | ||||
|     }, | ||||
| 
 | ||||
|     // Add other columns as needed
 | ||||
|     { | ||||
|       field: "actions", | ||||
|       headerName: "Actions", | ||||
|       width: 150, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div> | ||||
|           <div | ||||
|             className="three-dots" | ||||
|             onClick={() => handleThreeDotsClick(row.usrGrp)} | ||||
|           > | ||||
|             <BsThreeDotsVertical /> | ||||
|           </div> | ||||
|           {selectedUserGroup === row.usrGrp && ( | ||||
|             <div className="popover"> | ||||
|               <button onClick={() => handleDelete(row.usrGrp)}>Delete</button> | ||||
|               {/* You can include other actions here */} | ||||
|             </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"> | ||||
|         User Group Maintenance | ||||
|       </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%" }} | ||||
|       > | ||||
|         <DataGrid | ||||
|           rows={userGroups} | ||||
|           columns={columns} | ||||
|           components={{ | ||||
|             Toolbar: () => ( | ||||
|               <CustomToolbar | ||||
|                 apiRef={apiRef} | ||||
|                 handleThreeDotsClick={handleThreeDotsClick} | ||||
|                 handleModal={handleModal} | ||||
|               /> | ||||
|             ), | ||||
|           }} | ||||
|           pageSize={10} | ||||
|           onGridReady={(gridApi) => { | ||||
|             apiRef.current = gridApi; | ||||
|           }} | ||||
|           className="bg-gray-400" | ||||
|         /> | ||||
|       </Box> | ||||
|       {/* Your modals and other components */} | ||||
|       {isModalOpen && ( | ||||
|         <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"> | ||||
|             <h2 className="text-xl font-bold mb-4">Modal Title</h2> | ||||
|             {/* Modal content here */} | ||||
|             <Button onClick={() => setIsModalOpen(false)}>Close</Button> | ||||
|           </div> | ||||
|         </div> | ||||
|       )} | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default UserMaintance; | ||||
|  | ||||
| @ -1,132 +1,132 @@ | ||||
|  /* .container { | ||||
|   font-family: Arial, sans-serif; | ||||
|   max-width: 2000px; | ||||
|   margin: 0 auto; | ||||
|   padding: 20px; | ||||
| } | ||||
| 
 | ||||
| h1 { | ||||
|   text-align: center; | ||||
|   margin-bottom: 20px; | ||||
| } | ||||
| 
 | ||||
| table { | ||||
|   width: 100%; | ||||
|   border-collapse: collapse; | ||||
|   margin: 0 auto;  | ||||
|   max-width: 2000px; | ||||
|    | ||||
| } | ||||
| 
 | ||||
| table th, | ||||
| table td { | ||||
|   border: 1px solid #ddd; | ||||
|   padding: 8px; | ||||
|   text-align: left; | ||||
| } | ||||
| 
 | ||||
| table th { | ||||
|   background-color: #f2f2f2; | ||||
| } | ||||
| 
 | ||||
| input[type='text'] { | ||||
|   width: 100%; | ||||
|   padding: 5px; | ||||
| } | ||||
| 
 | ||||
| button { | ||||
|   padding: 8px 12px; | ||||
|   background-color: #007bff; | ||||
|   color: #fff; | ||||
|   border: none; | ||||
|   cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| button:hover { | ||||
|   background-color: #0056b3; | ||||
| } | ||||
| 
 | ||||
| label { | ||||
|   margin-right: 10px; | ||||
| } | ||||
| 
 | ||||
| select { | ||||
|   padding: 5px; | ||||
| } | ||||
| 
 | ||||
| .modal { | ||||
|   position: fixed; | ||||
|   top: 0; | ||||
|   left: 0; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   background-color: rgba(0, 0, 0, 0.5); | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
| } | ||||
| 
 | ||||
| .modal-content { | ||||
|   background-color: #fff; | ||||
|   padding: 20px; | ||||
|   border-radius: 5px; | ||||
|   box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); | ||||
| } | ||||
| 
 | ||||
| .modal-content input { | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| 
 | ||||
| .modal-content button { | ||||
|   margin-top: 10px; | ||||
| } | ||||
| 
 | ||||
| .update-modal { | ||||
|   position: fixed; | ||||
|   top: 0; | ||||
|   left: 0; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   background-color: rgba(0, 0, 0, 0.5); | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
| } | ||||
| 
 | ||||
| .update-modal-content { | ||||
|   background-color: #fff; | ||||
|   padding: 20px; | ||||
|   border-radius: 5px; | ||||
|   box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); | ||||
| } | ||||
| 
 | ||||
| .update-modal-content input { | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| 
 | ||||
| .update-modal-content button { | ||||
|   margin-top: 10px; | ||||
| } | ||||
| .spinner { | ||||
|   display: inline-block; | ||||
|   width: 40px; | ||||
|   height: 40px; | ||||
|   border: 4px solid rgba(0, 0, 0, 0.1); | ||||
|   border-left-color: #7983ff;  | ||||
|   border-radius: 50%; | ||||
|   animation: spin 1s linear infinite;  | ||||
| } | ||||
| 
 | ||||
| @keyframes spin { | ||||
|   to { | ||||
|     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'); | ||||
| .custom-header, .custom-cell { | ||||
|   font-family: 'PT Serif", serif ';  | ||||
|    | ||||
|   font-style: normal; | ||||
|   font-weight: bold; | ||||
| } | ||||
|  /* .container { | ||||
|   font-family: Arial, sans-serif; | ||||
|   max-width: 2000px; | ||||
|   margin: 0 auto; | ||||
|   padding: 20px; | ||||
| } | ||||
| 
 | ||||
| h1 { | ||||
|   text-align: center; | ||||
|   margin-bottom: 20px; | ||||
| } | ||||
| 
 | ||||
| table { | ||||
|   width: 100%; | ||||
|   border-collapse: collapse; | ||||
|   margin: 0 auto;  | ||||
|   max-width: 2000px; | ||||
|    | ||||
| } | ||||
| 
 | ||||
| table th, | ||||
| table td { | ||||
|   border: 1px solid #ddd; | ||||
|   padding: 8px; | ||||
|   text-align: left; | ||||
| } | ||||
| 
 | ||||
| table th { | ||||
|   background-color: #f2f2f2; | ||||
| } | ||||
| 
 | ||||
| input[type='text'] { | ||||
|   width: 100%; | ||||
|   padding: 5px; | ||||
| } | ||||
| 
 | ||||
| button { | ||||
|   padding: 8px 12px; | ||||
|   background-color: #007bff; | ||||
|   color: #fff; | ||||
|   border: none; | ||||
|   cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| button:hover { | ||||
|   background-color: #0056b3; | ||||
| } | ||||
| 
 | ||||
| label { | ||||
|   margin-right: 10px; | ||||
| } | ||||
| 
 | ||||
| select { | ||||
|   padding: 5px; | ||||
| } | ||||
| 
 | ||||
| .modal { | ||||
|   position: fixed; | ||||
|   top: 0; | ||||
|   left: 0; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   background-color: rgba(0, 0, 0, 0.5); | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
| } | ||||
| 
 | ||||
| .modal-content { | ||||
|   background-color: #fff; | ||||
|   padding: 20px; | ||||
|   border-radius: 5px; | ||||
|   box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); | ||||
| } | ||||
| 
 | ||||
| .modal-content input { | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| 
 | ||||
| .modal-content button { | ||||
|   margin-top: 10px; | ||||
| } | ||||
| 
 | ||||
| .update-modal { | ||||
|   position: fixed; | ||||
|   top: 0; | ||||
|   left: 0; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   background-color: rgba(0, 0, 0, 0.5); | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
| } | ||||
| 
 | ||||
| .update-modal-content { | ||||
|   background-color: #fff; | ||||
|   padding: 20px; | ||||
|   border-radius: 5px; | ||||
|   box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); | ||||
| } | ||||
| 
 | ||||
| .update-modal-content input { | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| 
 | ||||
| .update-modal-content button { | ||||
|   margin-top: 10px; | ||||
| } | ||||
| .spinner { | ||||
|   display: inline-block; | ||||
|   width: 40px; | ||||
|   height: 40px; | ||||
|   border: 4px solid rgba(0, 0, 0, 0.1); | ||||
|   border-left-color: #7983ff;  | ||||
|   border-radius: 50%; | ||||
|   animation: spin 1s linear infinite;  | ||||
| } | ||||
| 
 | ||||
| @keyframes spin { | ||||
|   to { | ||||
|     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'); | ||||
| .custom-header, .custom-cell { | ||||
|   font-family: 'PT Serif", serif ';  | ||||
|    | ||||
|   font-style: normal; | ||||
|   font-weight: bold; | ||||
| } | ||||
|  | ||||
| @ -1,169 +1,168 @@ | ||||
| import React, { useState, useEffect, useRef } from "react"; | ||||
| import { Box, Button } from "@mui/material"; | ||||
| import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; | ||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||
| import { faEllipsisV } from "@fortawesome/free-solid-svg-icons"; | ||||
| import Modal from "./Modal"; // Import your Modal component
 | ||||
| import UpdateModal from "./UpdateModal"; // Import your UpdateModal component
 | ||||
| import "./UserMaintance.css"; | ||||
| 
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) { | ||||
|   const handleGoToPage1 = () => { | ||||
|     if (apiRef.current) { | ||||
|       apiRef.current.setPage(1); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <GridToolbarContainer> | ||||
|       <Button onClick={handleGoToPage1}>Go to page 1</Button> | ||||
|       <Button onClick={handleModal}>+</Button> | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function UserMaintance() { | ||||
|   const [users, setUsers] = useState([]); | ||||
|   const [selectedUser, setSelectedUser] = useState(null); | ||||
|   const [selectedUserForUpdate, setSelectedUserForUpdate] = useState(null); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const [isUpdateModalOpen, setIsUpdateModalOpen] = useState(false); | ||||
|   const [newUser, setNewUser] = useState({ | ||||
|     userId: "", | ||||
|     username: "", | ||||
|     fullName: "", | ||||
|     email: "", | ||||
| 
 | ||||
|     usrGrpName: "", | ||||
|   }); | ||||
|   const apiRef = useRef(null); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("token"); | ||||
|       console.log("object", token); | ||||
|       try { | ||||
|         const response = await fetch(`${api}/api/getAllAppUser`, { | ||||
|           headers: { | ||||
|             Authorization: `Bearer ${token}`, | ||||
|           }, | ||||
|         }); | ||||
|         const data = await response.json(); | ||||
|         const usersWithIds = data.map((user, index) => ({ | ||||
|           ...user, | ||||
|           id: index + 1, | ||||
|         })); | ||||
|         setUsers(usersWithIds); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (userId) => { | ||||
|     setSelectedUser(userId === selectedUser ? null : userId); | ||||
|   }; | ||||
| 
 | ||||
|   const handleDelete = (userId) => { | ||||
|     console.log("Delete user with ID:", userId); | ||||
|   }; | ||||
| 
 | ||||
|   const handleUpdate = (user) => { | ||||
|     setSelectedUserForUpdate(user); | ||||
|     setIsUpdateModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   const handleModal = () => { | ||||
|     setIsModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   const handleModalSave = (data) => { | ||||
|     setUsers((prevUsers) => [ | ||||
|       ...prevUsers, | ||||
|       { ...data, id: prevUsers.length + 1 }, | ||||
|     ]); | ||||
|     setIsModalOpen(false); | ||||
|   }; | ||||
| 
 | ||||
|   const handleUpdateSave = () => { | ||||
|     setIsUpdateModalOpen(false); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { field: "userId", headerName: "User ID", width: 200 }, | ||||
|     { field: "username", headerName: "Username", width: 200 }, | ||||
|     { field: "fullName", headerName: "Full Name", width: 200 }, | ||||
|     { field: "email", headerName: "Email", width: 200 }, | ||||
|     { field: "usrGrpName", headerName: "User Group", width: 150 }, | ||||
|     { | ||||
|       field: "actions", | ||||
|       headerName: "Actions", | ||||
|       width: 100, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div> | ||||
|           <div | ||||
|             className="three-dots" | ||||
|             onClick={() => handleThreeDotsClick(row.userId)} | ||||
|           > | ||||
|             <FontAwesomeIcon icon={faEllipsisV} /> | ||||
|           </div> | ||||
|           {selectedUser === row.userId && ( | ||||
|             <div className="popover"> | ||||
|               <button onClick={() => handleDelete(row.userId)}>Delete</button> | ||||
|               <button onClick={() => handleUpdate(row)}>Update</button> | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ), | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   return ( | ||||
|     <Box | ||||
|       sx={{ height: "calc(100vh - 150px)", width: "100%", overflowX: "auto" }} | ||||
|     > | ||||
|       <div className="text-center text-3xl text-white bg-gray-400"> | ||||
|         User Maintenance | ||||
|       </div> | ||||
|       <DataGrid | ||||
|         className="bg-gray-400" | ||||
|         rows={users} | ||||
|         columns={columns} | ||||
|         components={{ | ||||
|           Toolbar: () => ( | ||||
|             <CustomToolbar | ||||
|               apiRef={apiRef} | ||||
|               handleThreeDotsClick={handleThreeDotsClick} | ||||
|               handleModal={handleModal} | ||||
|             /> | ||||
|           ), | ||||
|         }} | ||||
|         pageSize={10} | ||||
|         onGridReady={(gridApi) => { | ||||
|           apiRef.current = gridApi; | ||||
|         }} | ||||
|       /> | ||||
|       {isModalOpen && ( | ||||
|         <Modal | ||||
|           setNewUser={setNewUser} | ||||
|           newUser={newUser} | ||||
|           onSave={handleModalSave} | ||||
|           onClose={() => setIsModalOpen(false)} | ||||
|         /> | ||||
|       )} | ||||
|       {isUpdateModalOpen && ( | ||||
|         <UpdateModal | ||||
|           user={selectedUserForUpdate} | ||||
|           onUpdate={handleUpdateSave} | ||||
|           onClose={() => setIsUpdateModalOpen(false)} | ||||
|         /> | ||||
|       )} | ||||
|     </Box> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default UserMaintance; | ||||
| import React, { useState, useEffect, useRef } from "react"; | ||||
| import { Box, Button } from "@mui/material"; | ||||
| import { DataGrid, GridToolbarContainer } from "@mui/x-data-grid"; | ||||
| import { BsThreeDotsVertical } from "react-icons/bs"; | ||||
| import Modal from "./Modal"; // Import your Modal component
 | ||||
| import UpdateModal from "./UpdateModal"; // Import your UpdateModal component
 | ||||
| import "./UserMaintance.css"; | ||||
| 
 | ||||
| const api = process.env.REACT_APP_API_BASE_URL; | ||||
| 
 | ||||
| function CustomToolbar({ apiRef, handleThreeDotsClick, handleModal }) { | ||||
|   const handleGoToPage1 = () => { | ||||
|     if (apiRef.current) { | ||||
|       apiRef.current.setPage(1); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <GridToolbarContainer> | ||||
|       <Button onClick={handleGoToPage1}>Go to page 1</Button> | ||||
|       <Button onClick={handleModal}>+</Button> | ||||
|     </GridToolbarContainer> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| function UserMaintance() { | ||||
|   const [users, setUsers] = useState([]); | ||||
|   const [selectedUser, setSelectedUser] = useState(null); | ||||
|   const [selectedUserForUpdate, setSelectedUserForUpdate] = useState(null); | ||||
|   const [isModalOpen, setIsModalOpen] = useState(false); | ||||
|   const [isUpdateModalOpen, setIsUpdateModalOpen] = useState(false); | ||||
|   const [newUser, setNewUser] = useState({ | ||||
|     userId: "", | ||||
|     username: "", | ||||
|     fullName: "", | ||||
|     email: "", | ||||
| 
 | ||||
|     usrGrpName: "", | ||||
|   }); | ||||
|   const apiRef = useRef(null); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchData = async () => { | ||||
|       const token = localStorage.getItem("token"); | ||||
|       console.log("object", token); | ||||
|       try { | ||||
|         const response = await fetch(`${api}/api/getAllAppUser`, { | ||||
|           headers: { | ||||
|             Authorization: `Bearer ${token}`, | ||||
|           }, | ||||
|         }); | ||||
|         const data = await response.json(); | ||||
|         const usersWithIds = data.map((user, index) => ({ | ||||
|           ...user, | ||||
|           id: index + 1, | ||||
|         })); | ||||
|         setUsers(usersWithIds); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching data:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchData(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleThreeDotsClick = (userId) => { | ||||
|     setSelectedUser(userId === selectedUser ? null : userId); | ||||
|   }; | ||||
| 
 | ||||
|   const handleDelete = (userId) => { | ||||
|     console.log("Delete user with ID:", userId); | ||||
|   }; | ||||
| 
 | ||||
|   const handleUpdate = (user) => { | ||||
|     setSelectedUserForUpdate(user); | ||||
|     setIsUpdateModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   const handleModal = () => { | ||||
|     setIsModalOpen(true); | ||||
|   }; | ||||
| 
 | ||||
|   const handleModalSave = (data) => { | ||||
|     setUsers((prevUsers) => [ | ||||
|       ...prevUsers, | ||||
|       { ...data, id: prevUsers.length + 1 }, | ||||
|     ]); | ||||
|     setIsModalOpen(false); | ||||
|   }; | ||||
| 
 | ||||
|   const handleUpdateSave = () => { | ||||
|     setIsUpdateModalOpen(false); | ||||
|   }; | ||||
| 
 | ||||
|   const columns = [ | ||||
|     { field: "userId", headerName: "User ID", width: 200 }, | ||||
|     { field: "username", headerName: "Username", width: 200 }, | ||||
|     { field: "fullName", headerName: "Full Name", width: 200 }, | ||||
|     { field: "email", headerName: "Email", width: 200 }, | ||||
|     { field: "usrGrpName", headerName: "User Group", width: 150 }, | ||||
|     { | ||||
|       field: "actions", | ||||
|       headerName: "Actions", | ||||
|       width: 100, | ||||
|       renderCell: ({ row }) => ( | ||||
|         <div> | ||||
|           <div | ||||
|             className="three-dots" | ||||
|             onClick={() => handleThreeDotsClick(row.userId)} | ||||
|           > | ||||
|             <BsThreeDotsVertical /> | ||||
|           </div> | ||||
|           {selectedUser === row.userId && ( | ||||
|             <div className="popover"> | ||||
|               <button onClick={() => handleDelete(row.userId)}>Delete</button> | ||||
|               <button onClick={() => handleUpdate(row)}>Update</button> | ||||
|             </div> | ||||
|           )} | ||||
|         </div> | ||||
|       ), | ||||
|     }, | ||||
|   ]; | ||||
| 
 | ||||
|   return ( | ||||
|     <Box | ||||
|       sx={{ height: "calc(100vh - 150px)", width: "100%", overflowX: "auto" }} | ||||
|     > | ||||
|       <div className="text-center text-3xl text-white bg-gray-400"> | ||||
|         User Maintenance | ||||
|       </div> | ||||
|       <DataGrid | ||||
|         className="bg-gray-400" | ||||
|         rows={users} | ||||
|         columns={columns} | ||||
|         components={{ | ||||
|           Toolbar: () => ( | ||||
|             <CustomToolbar | ||||
|               apiRef={apiRef} | ||||
|               handleThreeDotsClick={handleThreeDotsClick} | ||||
|               handleModal={handleModal} | ||||
|             /> | ||||
|           ), | ||||
|         }} | ||||
|         pageSize={10} | ||||
|         onGridReady={(gridApi) => { | ||||
|           apiRef.current = gridApi; | ||||
|         }} | ||||
|       /> | ||||
|       {isModalOpen && ( | ||||
|         <Modal | ||||
|           setNewUser={setNewUser} | ||||
|           newUser={newUser} | ||||
|           onSave={handleModalSave} | ||||
|           onClose={() => setIsModalOpen(false)} | ||||
|         /> | ||||
|       )} | ||||
|       {isUpdateModalOpen && ( | ||||
|         <UpdateModal | ||||
|           user={selectedUserForUpdate} | ||||
|           onUpdate={handleUpdateSave} | ||||
|           onClose={() => setIsUpdateModalOpen(false)} | ||||
|         /> | ||||
|       )} | ||||
|     </Box> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default UserMaintance; | ||||
|  | ||||
| @ -1,123 +1,126 @@ | ||||
| /* Global Styles */ | ||||
| body { | ||||
|   font-family: 'Roboto', sans-serif; | ||||
|   background-color: #f4f6f8; | ||||
|   color: #333; | ||||
|   margin: 0; | ||||
|   padding: 0; | ||||
| } | ||||
| 
 | ||||
| .dashboard { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   height: 100vh; | ||||
| } | ||||
| 
 | ||||
| /* Horizontal Navbar */ | ||||
| .horizontal-navbar { | ||||
|   display: flex; | ||||
|   justify-content: space-between; | ||||
|   align-items: center; | ||||
|   background-color: #2c3e50; | ||||
|   color: #ecf0f1; | ||||
|   padding: 10px 20px; | ||||
| } | ||||
| 
 | ||||
| .horizontal-navbar h3 { | ||||
|   margin: 0; | ||||
|   font-size: 24px; | ||||
| } | ||||
| 
 | ||||
| .nav { | ||||
|   display: flex; | ||||
|   gap: 20px; | ||||
| } | ||||
| 
 | ||||
| .nav-link { | ||||
|   color: #ecf0f1; | ||||
|   text-decoration: none; | ||||
|   font-size: 18px; | ||||
|   transition: color 0.3s; | ||||
| } | ||||
| 
 | ||||
| .nav-link:hover { | ||||
|   color: #3498db; | ||||
| } | ||||
| 
 | ||||
| button { | ||||
|   background-color: #e74c3c; | ||||
|   color: #ecf0f1; | ||||
|   border: none; | ||||
|   padding: 10px 20px; | ||||
|   border-radius: 5px; | ||||
|   cursor: pointer; | ||||
|   transition: background-color 0.3s; | ||||
| } | ||||
| 
 | ||||
| button:hover { | ||||
|   background-color: #c0392b; | ||||
| } | ||||
| 
 | ||||
| /* Content */ | ||||
| .content { | ||||
|   display: flex; | ||||
|   flex: 1; | ||||
|   overflow: hidden; | ||||
| } | ||||
| 
 | ||||
| .sidebar-content-wrapper { | ||||
|   display: flex; | ||||
|   flex: 1; | ||||
|   overflow: hidden; | ||||
| } | ||||
| 
 | ||||
| /* Sidebar */ | ||||
| .sidebar { | ||||
|   width: 250px; | ||||
|   background-color: #34495e; | ||||
|   color: #ecf0f1; | ||||
|   transition: width 0.3s; | ||||
|   overflow: auto; | ||||
| } | ||||
| 
 | ||||
| .sidebar.collapsed { | ||||
|   width: 80px; | ||||
| } | ||||
| 
 | ||||
| .sidebar-content-wrapper .sidebar ul { | ||||
|   list-style: none; | ||||
|   padding: 0; | ||||
|   margin: 0; | ||||
| } | ||||
| 
 | ||||
| .sidebar-content-wrapper .sidebar ul li { | ||||
|   padding: 15px 20px; | ||||
|   cursor: pointer; | ||||
|   transition: background-color 0.3s; | ||||
| } | ||||
| 
 | ||||
| .sidebar-content-wrapper .sidebar ul li:hover { | ||||
|   background-color: #2c3e50; | ||||
| } | ||||
| 
 | ||||
| .sidebar-content-wrapper .sidebar ul li.active { | ||||
|   background-color: #3498db; | ||||
| } | ||||
| 
 | ||||
| .sidebar-content-wrapper .sidebar .toggle-btn { | ||||
|   text-align: center; | ||||
|   padding: 10px; | ||||
|   cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| /* Main Content */ | ||||
| .main-content { | ||||
|   flex: 1; | ||||
|   padding: 20px; | ||||
|   background-color: #ecf0f1; | ||||
|   overflow-y: auto; | ||||
| } | ||||
| 
 | ||||
| .main-content h3 { | ||||
|   margin-top: 0; | ||||
| } | ||||
| /* Global Styles */ | ||||
| body { | ||||
|   font-family: 'Roboto', sans-serif; | ||||
|   background-color: #f4f6f8; | ||||
|   color: #333; | ||||
|   margin: 0; | ||||
|   padding: 0; | ||||
| } | ||||
| 
 | ||||
| .dashboard { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   height: 100vh; | ||||
| } | ||||
| 
 | ||||
| /* Horizontal Navbar */ | ||||
| .horizontal-navbar { | ||||
|   display: flex; | ||||
|   justify-content: space-between; | ||||
|   align-items: center; | ||||
|   background-color: #2c3e50; | ||||
|   color: #ecf0f1; | ||||
|   padding: 10px 20px; | ||||
| } | ||||
| 
 | ||||
| .horizontal-navbar h3 { | ||||
|   margin: 0; | ||||
|   font-size: 24px; | ||||
| } | ||||
| 
 | ||||
| .nav { | ||||
|   display: flex; | ||||
|   gap: 20px; | ||||
| } | ||||
| 
 | ||||
| .nav-link { | ||||
|   color: #ecf0f1; | ||||
|   text-decoration: none; | ||||
|   font-size: 18px; | ||||
|   transition: color 0.3s; | ||||
| } | ||||
| 
 | ||||
| .nav-link:hover { | ||||
|   color: #3498db; | ||||
| } | ||||
| 
 | ||||
| button { | ||||
|   background-color: #e74c3c; | ||||
|   color: #ecf0f1; | ||||
|   border: none; | ||||
|   padding: 10px 20px; | ||||
|   border-radius: 5px; | ||||
|   cursor: pointer; | ||||
|   transition: background-color 0.3s; | ||||
| } | ||||
| 
 | ||||
| button:hover { | ||||
|   background-color: #c0392b; | ||||
| } | ||||
| 
 | ||||
| /* Content */ | ||||
| .content { | ||||
|   display: flex; | ||||
|   flex: 1; | ||||
|   overflow: hidden; | ||||
| } | ||||
| 
 | ||||
| .sidebar-content-wrapper { | ||||
|   display: flex; | ||||
|   flex: 1; | ||||
|   overflow: hidden; | ||||
| } | ||||
| 
 | ||||
| /* Sidebar */ | ||||
| .sidebar { | ||||
|   width: 250px; | ||||
|   background-color: #34495e; | ||||
|   color: #ecf0f1; | ||||
|   transition: width 0.3s; | ||||
|   overflow: auto; | ||||
| } | ||||
| 
 | ||||
| .sidebar.collapsed { | ||||
|   width: 80px; | ||||
| } | ||||
| 
 | ||||
| .sidebar-content-wrapper .sidebar ul { | ||||
|   list-style: none; | ||||
|   padding: 0; | ||||
|   margin: 0; | ||||
| } | ||||
| 
 | ||||
| .sidebar-content-wrapper .sidebar ul li { | ||||
|   padding: 15px 20px; | ||||
|   cursor: pointer; | ||||
|   transition: background-color 0.3s; | ||||
| } | ||||
| 
 | ||||
| .sidebar-content-wrapper .sidebar ul li:hover { | ||||
|   background-color: #2c3e50; | ||||
| } | ||||
| 
 | ||||
| .sidebar-content-wrapper .sidebar ul li.active { | ||||
|   background-color: #3498db; | ||||
| } | ||||
| 
 | ||||
| .sidebar-content-wrapper .sidebar .toggle-btn { | ||||
|   text-align: center; | ||||
|   padding: 10px; | ||||
|   cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| /* Main Content */ | ||||
| .main-content { | ||||
|   flex: 1; | ||||
|   padding: 20px; | ||||
|   background-color: #ecf0f1; | ||||
|   overflow-y: auto; | ||||
| } | ||||
| 
 | ||||
| .main-content h3 { | ||||
|   margin-top: 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1,177 +1,202 @@ | ||||
| import React, { useState, useEffect } from "react"; | ||||
| import Sidebar from "./sidebar"; | ||||
| import { useNavigate } from "react-router-dom"; | ||||
| import UserMaintanceComponent from "./UserMaintance"; | ||||
| import UserGroupMaintanceComponent from "./UserGroupMaintance/UserGroupMaintance"; | ||||
| import MenuMaintanceComponent from "./MenuMaintance/MenuMaintance"; | ||||
| import MenuAccessControlComponent from "./MenuAccessControl/MenuAccessControl"; | ||||
| import SystemParametersComponent from "./SystemParameters/SystemParameters"; | ||||
| import AccessTypeComponent from "./AccessType/AccessType"; | ||||
| import ApiRegistery from "./ApiRegistery/ApiRegistery"; | ||||
| import TokenRegistery from "./TokenRegistery/TokenRegistery"; | ||||
| import HomePage from "./HomePage"; | ||||
| import Setup from "./Setup.js"; | ||||
| import Report from "./Report"; | ||||
| import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||||
| import { | ||||
|   faCog, | ||||
|   faUsers, | ||||
|   faSignOutAlt, | ||||
|   faHome, | ||||
| } from "@fortawesome/free-solid-svg-icons"; | ||||
| 
 | ||||
| const Dashboard = () => { | ||||
|   const navigate = useNavigate(); | ||||
|   const [menus, setMenus] = useState([]); | ||||
|   const [selectedUserMaintance, setSelectedUserMaintance] = useState(null); | ||||
|   const [sidebarCollapsed, setSidebarCollapsed] = useState(false); | ||||
|   const [content, setContent] = useState(""); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchMenusData = async () => { | ||||
|       const token = localStorage.getItem("token"); | ||||
| 
 | ||||
|       const apiUrl = `${process.env.REACT_APP_API_BASE_URL}/fndMenu/menuloadbyuser`; | ||||
|       console.log("Fetching menus from API:", apiUrl); | ||||
| 
 | ||||
|       try { | ||||
|         const response = await fetch(apiUrl, { | ||||
|           headers: { | ||||
|             Authorization: `Bearer ${token}`, | ||||
|           }, | ||||
|         }); | ||||
| 
 | ||||
|         if (response.ok) { | ||||
|           const menuData = await response.json(); | ||||
|           setMenus(menuData); | ||||
|         } else { | ||||
|           const errorText = await response.text(); | ||||
|           console.error( | ||||
|             "Failed to fetch menus. Status:", | ||||
|             response.status, | ||||
|             "Response:", | ||||
|             errorText | ||||
|           ); | ||||
|         } | ||||
|       } catch (error) { | ||||
|         console.error("Error during menu fetch:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchMenusData(); | ||||
|   }, [navigate]); | ||||
| 
 | ||||
|   const handleMenuItemClick = (menuItem) => { | ||||
|     setSelectedUserMaintance(menuItem); | ||||
|     setContent(menuItem.menuItemDesc); // Update content based on clicked menu item
 | ||||
|   }; | ||||
| 
 | ||||
|   const handleHomeClick = () => { | ||||
|     setSelectedUserMaintance(null); | ||||
|     setContent("Home"); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSetupClick = () => { | ||||
|     setSelectedUserMaintance(null); | ||||
|     setContent("Setup"); | ||||
|   }; | ||||
| 
 | ||||
|   const handleReportClick = () => { | ||||
|     setSelectedUserMaintance(null); | ||||
|     setContent("Report"); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSidebarToggle = () => { | ||||
|     setSidebarCollapsed(!sidebarCollapsed); | ||||
|   }; | ||||
| 
 | ||||
|   const handleLogout = () => { | ||||
|     localStorage.removeItem("authToken"); | ||||
|     localStorage.removeItem("user"); | ||||
|     navigate("/"); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="flex flex-col h-screen"> | ||||
|       <div className="flex justify-between items-center bg-gray-800 text-white p-4"> | ||||
|         <h3 className="text-2xl">Dashboard</h3> | ||||
|         <nav className="flex space-x-4"> | ||||
|           <a className="text-white" href="#" onClick={handleHomeClick}> | ||||
|             <FontAwesomeIcon icon={faHome} /> | ||||
|           </a> | ||||
|           <a className="text-white" href="#" onClick={handleSetupClick}> | ||||
|             <FontAwesomeIcon icon={faCog} /> | ||||
|           </a> | ||||
|           <a className="text-white" href="#" onClick={handleReportClick}> | ||||
|             <FontAwesomeIcon icon={faUsers} /> | ||||
|           </a> | ||||
|         </nav> | ||||
|         <button | ||||
|           className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded" | ||||
|           onClick={handleLogout} | ||||
|         > | ||||
|           <FontAwesomeIcon icon={faSignOutAlt} /> Logout | ||||
|         </button> | ||||
|       </div> | ||||
| 
 | ||||
|       <div className="flex flex-1 overflow-hidden"> | ||||
|         <div | ||||
|           className={`bg-gray-700 text-white transition-all duration-300 ${ | ||||
|             sidebarCollapsed ? "w-16" : "w-64" | ||||
|           } min-w-16`}
 | ||||
|         > | ||||
|           <div className="flex justify-center p-2"> | ||||
|             <button onClick={handleSidebarToggle} className="text-white"> | ||||
|               {sidebarCollapsed ? ">>" : "<<"} | ||||
|             </button> | ||||
|           </div> | ||||
|           <Sidebar | ||||
|             menus={menus} | ||||
|             handleMenuItemClick={handleMenuItemClick} | ||||
|             collapsed={sidebarCollapsed} | ||||
|             setCollapsed={setSidebarCollapsed} | ||||
|           /> | ||||
|         </div> | ||||
| 
 | ||||
|         <div className="flex-1 p-6 overflow-auto bg-gray-100"> | ||||
|           {content === "Setup" ? ( | ||||
|             <Setup /> | ||||
|           ) : content === "Home" ? ( | ||||
|             <HomePage /> | ||||
|           ) : content === "Report" ? ( | ||||
|             <Report /> | ||||
|           ) : selectedUserMaintance ? ( | ||||
|             <div> | ||||
|               <h3 className="text-2xl mb-4"> | ||||
|                 {selectedUserMaintance.menuItemDesc} | ||||
|               </h3> | ||||
|               {selectedUserMaintance.menuItemDesc === "User Maintance" ? ( | ||||
|                 <UserMaintanceComponent /> | ||||
|               ) : selectedUserMaintance.menuItemDesc === | ||||
|                 "User Group Maintance" ? ( | ||||
|                 <UserGroupMaintanceComponent /> | ||||
|               ) : selectedUserMaintance.menuItemDesc === "Menu Maintance" ? ( | ||||
|                 <MenuMaintanceComponent /> | ||||
|               ) : selectedUserMaintance.menuItemDesc === | ||||
|                 "Menu Access Control" ? ( | ||||
|                 <MenuAccessControlComponent /> | ||||
|               ) : selectedUserMaintance.menuItemDesc === "System Parameters" ? ( | ||||
|                 <SystemParametersComponent /> | ||||
|               ) : selectedUserMaintance.menuItemDesc === "Access Type" ? ( | ||||
|                 <AccessTypeComponent /> | ||||
|               ) : selectedUserMaintance.menuItemDesc === "Api Registery" ? ( | ||||
|                 <ApiRegistery /> | ||||
|               ) : selectedUserMaintance.menuItemDesc === "Token Registery" ? ( | ||||
|                 <TokenRegistery /> | ||||
|               ) : null} | ||||
|             </div> | ||||
|           ) : ( | ||||
|             <HomePage /> | ||||
|           )} | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default Dashboard; | ||||
| /* eslint-disable jsx-a11y/anchor-is-valid */ | ||||
| import React, { useState, useEffect } from "react"; | ||||
| import Sidebar from "./sidebar"; | ||||
| import { useNavigate } from "react-router-dom"; | ||||
| import UserMaintanceComponent from "./UserMaintance"; | ||||
| import UserGroupMaintanceComponent from "./UserGroupMaintance/UserGroupMaintance"; | ||||
| import MenuMaintanceComponent from "./MenuMaintance/MenuMaintance"; | ||||
| import MenuAccessControlComponent from "./MenuAccessControl/MenuAccessControl"; | ||||
| import SystemParametersComponent from "./SystemParameters/SystemParameters"; | ||||
| // import AccessTypeComponent from "./AccessType/AccessType";
 | ||||
| import ApiRegistery from "./ApiRegistery/ApiRegistery"; | ||||
| import TokenRegistery from "./TokenRegistery/TokenRegistery"; | ||||
| import HomePage from "./HomePage"; | ||||
| import Setup from "./Setup.js"; | ||||
| import Report from "./Report"; | ||||
| import { FaCog, FaUsers, FaSignOutAlt, FaHome, FaChartBar } from "react-icons/fa"; | ||||
| 
 | ||||
| const Dashboard = () => { | ||||
|   const navigate = useNavigate(); | ||||
|   const [menus, setMenus] = useState([]); | ||||
|   const [selectedUserMaintance, setSelectedUserMaintance] = useState(null); | ||||
|   const [sidebarCollapsed, setSidebarCollapsed] = useState(false); | ||||
|   const [content, setContent] = useState(""); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchMenusData = async () => { | ||||
|       const token = localStorage.getItem("authtoken"); | ||||
| 
 | ||||
|       const apiUrl = `${process.env.REACT_APP_API_BASE_URL}/fndMenu/menuloadbyuser`; | ||||
|       console.log("Fetching menus from API:", apiUrl); | ||||
| 
 | ||||
|       try { | ||||
|         const response = await fetch(apiUrl, { | ||||
|           method: "GET", | ||||
|           headers: { | ||||
|             "Content-Type": "application/json", | ||||
|             Authorization: `Bearer ${token}`, | ||||
|           }, | ||||
|         }); | ||||
| 
 | ||||
|         if (response.ok) { | ||||
|           const menuData = await response.json(); | ||||
|           setMenus(menuData); | ||||
|         } else { | ||||
|           const errorText = await response.text(); | ||||
|           console.error( | ||||
|             "Failed to fetch menus. Status:", | ||||
|             response.status, | ||||
|             "Response:", | ||||
|             errorText | ||||
|           ); | ||||
|         } | ||||
|       } catch (error) { | ||||
|         console.error("Error during menu fetch:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchMenusData(); | ||||
|   }, [navigate]); | ||||
| 
 | ||||
|   const handleMenuItemClick = (menuItem) => { | ||||
|     setSelectedUserMaintance(menuItem); | ||||
|     setContent(menuItem.menuItemDesc); // Update content based on clicked menu item
 | ||||
|   }; | ||||
| 
 | ||||
|   const handleHomeClick = () => { | ||||
|     setSelectedUserMaintance(null); | ||||
|     setContent("Home"); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSetupClick = () => { | ||||
|     setSelectedUserMaintance(null); | ||||
|     setContent("Setup"); | ||||
|   }; | ||||
| 
 | ||||
|   const handleReportClick = () => { | ||||
|     setSelectedUserMaintance(null); | ||||
|     setContent("Report"); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSidebarToggle = () => { | ||||
|     setSidebarCollapsed(!sidebarCollapsed); | ||||
|   }; | ||||
| 
 | ||||
|   const handleLogout = () => { | ||||
|     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 */} | ||||
|       <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 items-center space-x-4"> | ||||
|           <h3 className="text-2xl font-bold">Dashboard</h3> | ||||
|           <div className="h-6 w-px bg-white/30"></div> | ||||
|           <nav className="flex space-x-6"> | ||||
|             <button  | ||||
|               onClick={handleHomeClick} | ||||
|               className="flex items-center space-x-2 hover:text-purple-200 transition-colors" | ||||
|             > | ||||
|               <FaHome className="w-5 h-5" /> | ||||
|               <span>Home</span> | ||||
|             </button> | ||||
|             <button  | ||||
|               onClick={handleSetupClick} | ||||
|               className="flex items-center space-x-2 hover:text-purple-200 transition-colors" | ||||
|             > | ||||
|               <FaCog className="w-5 h-5" /> | ||||
|               <span>Setup</span> | ||||
|             </button> | ||||
|             <button  | ||||
|               onClick={handleReportClick} | ||||
|               className="flex items-center space-x-2 hover:text-purple-200 transition-colors" | ||||
|             > | ||||
|               <FaChartBar className="w-5 h-5" /> | ||||
|               <span>Reports</span> | ||||
|             </button> | ||||
|           </nav> | ||||
|         </div> | ||||
|         <button | ||||
|           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" | ||||
|           onClick={handleLogout} | ||||
|         > | ||||
|           <FaSignOutAlt className="w-5 h-5" /> | ||||
|           <span>Logout</span> | ||||
|         </button> | ||||
|       </div> | ||||
| 
 | ||||
|       <div className="flex flex-1 overflow-hidden"> | ||||
|         {/* Sidebar */} | ||||
|         <div | ||||
|           className={`bg-gradient-to-b from-purple-700 to-indigo-800 text-white transition-all duration-300 ${ | ||||
|             sidebarCollapsed ? "w-16" : "w-64" | ||||
|           } min-w-16 shadow-xl`}
 | ||||
|         > | ||||
|           <div className="flex justify-end p-2"> | ||||
|             <button  | ||||
|               onClick={handleSidebarToggle}  | ||||
|               className="text-white/80 hover:text-white bg-white/10 hover:bg-white/20 p-2 rounded-lg transition-all duration-200" | ||||
|             > | ||||
|               {sidebarCollapsed ? ">>" : "<<"} | ||||
|             </button> | ||||
|           </div> | ||||
|           <Sidebar | ||||
|             menus={menus} | ||||
|             handleMenuItemClick={handleMenuItemClick} | ||||
|             collapsed={sidebarCollapsed} | ||||
|             setCollapsed={setSidebarCollapsed} | ||||
|           /> | ||||
|         </div> | ||||
| 
 | ||||
|         {/* Main Content Area */} | ||||
|         <div className="flex-1 p-6 overflow-auto bg-gradient-to-br from-purple-50 via-white to-blue-50"> | ||||
|           <div className="max-w-7xl mx-auto"> | ||||
|             {content === "Setup" ? ( | ||||
|               <div className="bg-white rounded-xl shadow-lg p-6"> | ||||
|                 <Setup /> | ||||
|               </div> | ||||
|             ) : content === "Home" ? ( | ||||
|               <div className="bg-white rounded-xl shadow-lg p-6"> | ||||
|                 <HomePage /> | ||||
|               </div> | ||||
|             ) : content === "Report" ? ( | ||||
|               <div className="bg-white rounded-xl shadow-lg p-6"> | ||||
|                 <Report /> | ||||
|               </div> | ||||
|             ) : selectedUserMaintance ? ( | ||||
|               <div className="bg-white rounded-xl shadow-lg p-6"> | ||||
|                 <h3 className="text-2xl font-bold text-gray-800 mb-6 pb-2 border-b border-purple-100"> | ||||
|                   {selectedUserMaintance.menuItemDesc} | ||||
|                 </h3> | ||||
|                 {selectedUserMaintance.menuItemDesc === "User Maintance" ? ( | ||||
|                   <UserMaintanceComponent /> | ||||
|                 ) : selectedUserMaintance.menuItemDesc === "User Group Maintance" ? ( | ||||
|                   <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'; | ||||
| 
 | ||||
| function App() { | ||||
|   const [formData, setFormData] = useState({ | ||||
|     name: '', | ||||
|     test: [ | ||||
|       { t1: '', t2: '' } // Initial test2
 | ||||
|     ] | ||||
|   }); | ||||
| 
 | ||||
|   const handleChange = (e, index) => { | ||||
|     const { name, value } = e.target; | ||||
|     if (name === 'name') { | ||||
|       setFormData({ ...formData, [name]: value }); | ||||
|     } else { | ||||
|       const updatedTests = [...formData.test]; | ||||
|       updatedTests[index][name] = value; | ||||
|       setFormData({ ...formData, test: updatedTests }); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleAddTest = () => { | ||||
|     setFormData({ | ||||
|       ...formData, | ||||
|       test: [...formData.test, { t1: '', t2: '' }] | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSubmit = (e) => { | ||||
|     e.preventDefault(); | ||||
|     console.log(formData); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="container"> | ||||
|       <form onSubmit={handleSubmit}> | ||||
|         <div className="form-group"> | ||||
|           <label htmlFor="name">Name:</label> | ||||
|           <input type="text" id="name" name="name" value={formData.name} onChange={handleChange} required /> | ||||
|         </div> | ||||
|         <hr /> | ||||
|         <h2>Test 2</h2> | ||||
|         {formData.test.map((test, index) => ( | ||||
|           <div key={index}> | ||||
|             <div className="form-group"> | ||||
|               <label htmlFor={`t1-${index}`}>Name:</label> | ||||
|               <input type="text" id={`t1-${index}`} name={`t1-${index}`} value={test.t1} onChange={(e) => handleChange(e, index)} required /> | ||||
|             </div> | ||||
|             <div className="form-group"> | ||||
|               <label htmlFor={`t2-${index}`}>Description:</label> | ||||
|               <input type="text" id={`t2-${index}`} name={`t2-${index}`} value={test.t2} onChange={(e) => handleChange(e, index)} required /> | ||||
|             </div> | ||||
|           </div> | ||||
|         ))} | ||||
|         <button type="button" onClick={handleAddTest}>Add Test</button> | ||||
|         <button type="submit">Submit</button> | ||||
|       </form> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default App; | ||||
| import React, { useState } from 'react'; | ||||
| 
 | ||||
| function App() { | ||||
|   const [formData, setFormData] = useState({ | ||||
|     name: '', | ||||
|     test: [ | ||||
|       { t1: '', t2: '' } // Initial test2
 | ||||
|     ] | ||||
|   }); | ||||
| 
 | ||||
|   const handleChange = (e, index) => { | ||||
|     const { name, value } = e.target; | ||||
|     if (name === 'name') { | ||||
|       setFormData({ ...formData, [name]: value }); | ||||
|     } else { | ||||
|       const updatedTests = [...formData.test]; | ||||
|       updatedTests[index][name] = value; | ||||
|       setFormData({ ...formData, test: updatedTests }); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleAddTest = () => { | ||||
|     setFormData({ | ||||
|       ...formData, | ||||
|       test: [...formData.test, { t1: '', t2: '' }] | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSubmit = (e) => { | ||||
|     e.preventDefault(); | ||||
|     console.log(formData); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="container"> | ||||
|       <form onSubmit={handleSubmit}> | ||||
|         <div className="form-group"> | ||||
|           <label htmlFor="name">Name:</label> | ||||
|           <input type="text" id="name" name="name" value={formData.name} onChange={handleChange} required /> | ||||
|         </div> | ||||
|         <hr /> | ||||
|         <h2>Test 2</h2> | ||||
|         {formData.test.map((test, index) => ( | ||||
|           <div key={index}> | ||||
|             <div className="form-group"> | ||||
|               <label htmlFor={`t1-${index}`}>Name:</label> | ||||
|               <input type="text" id={`t1-${index}`} name={`t1-${index}`} value={test.t1} onChange={(e) => handleChange(e, index)} required /> | ||||
|             </div> | ||||
|             <div className="form-group"> | ||||
|               <label htmlFor={`t2-${index}`}>Description:</label> | ||||
|               <input type="text" id={`t2-${index}`} name={`t2-${index}`} value={test.t2} onChange={(e) => handleChange(e, index)} required /> | ||||
|             </div> | ||||
|           </div> | ||||
|         ))} | ||||
|         <button type="button" onClick={handleAddTest}>Add Test</button> | ||||
|         <button type="submit">Submit</button> | ||||
|       </form> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default App; | ||||
|  | ||||
| @ -1,73 +1,73 @@ | ||||
| import React, { useState } from 'react'; | ||||
| 
 | ||||
| function MyForm() { | ||||
|   const [formData, setFormData] = useState({ | ||||
|     name: '', | ||||
|     test2: { name: '', description: '' } | ||||
|   }); | ||||
| 
 | ||||
|   const handleChange = (e) => { | ||||
|     const { name, value } = e.target; | ||||
|     setFormData({ | ||||
|       ...formData, | ||||
|       [name]: value | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleTest2Change = (e) => { | ||||
|     const { name, value } = e.target; | ||||
|     setFormData({ | ||||
|       ...formData, | ||||
|       test2: { | ||||
|         ...formData.test2, | ||||
|         [name]: value | ||||
|       } | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSubmit = (e) => { | ||||
|     e.preventDefault(); | ||||
|     console.log(formData); | ||||
|     // we can send this data to our server
 | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <form onSubmit={handleSubmit}> | ||||
|       <div> | ||||
|         <label htmlFor="name">Name:</label> | ||||
|         <input | ||||
|           type="text" | ||||
|           id="name" | ||||
|           name="name" | ||||
|           value={formData.name} | ||||
|           onChange={handleChange} | ||||
|         /> | ||||
|       </div> | ||||
|       <hr /> | ||||
|       <h2>Test 2</h2> | ||||
|       <div> | ||||
|         <label htmlFor="test2Name">Name:</label> | ||||
|         <input | ||||
|           type="text" | ||||
|           id="test2Name" | ||||
|           name="name" | ||||
|           value={formData.test2.name} | ||||
|           onChange={handleTest2Change} | ||||
|         /> | ||||
|       </div> | ||||
|       <div> | ||||
|         <label htmlFor="test2Description">Description:</label> | ||||
|         <input | ||||
|           type="text" | ||||
|           id="test2Description" | ||||
|           name="description" | ||||
|           value={formData.test2.description} | ||||
|           onChange={handleTest2Change} | ||||
|         /> | ||||
|       </div> | ||||
|       <button type="submit">Submit</button> | ||||
|     </form> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default MyForm; | ||||
| import React, { useState } from 'react'; | ||||
| 
 | ||||
| function MyForm() { | ||||
|   const [formData, setFormData] = useState({ | ||||
|     name: '', | ||||
|     test2: { name: '', description: '' } | ||||
|   }); | ||||
| 
 | ||||
|   const handleChange = (e) => { | ||||
|     const { name, value } = e.target; | ||||
|     setFormData({ | ||||
|       ...formData, | ||||
|       [name]: value | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleTest2Change = (e) => { | ||||
|     const { name, value } = e.target; | ||||
|     setFormData({ | ||||
|       ...formData, | ||||
|       test2: { | ||||
|         ...formData.test2, | ||||
|         [name]: value | ||||
|       } | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   const handleSubmit = (e) => { | ||||
|     e.preventDefault(); | ||||
|     console.log(formData); | ||||
|     // we can send this data to our server
 | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <form onSubmit={handleSubmit}> | ||||
|       <div> | ||||
|         <label htmlFor="name">Name:</label> | ||||
|         <input | ||||
|           type="text" | ||||
|           id="name" | ||||
|           name="name" | ||||
|           value={formData.name} | ||||
|           onChange={handleChange} | ||||
|         /> | ||||
|       </div> | ||||
|       <hr /> | ||||
|       <h2>Test 2</h2> | ||||
|       <div> | ||||
|         <label htmlFor="test2Name">Name:</label> | ||||
|         <input | ||||
|           type="text" | ||||
|           id="test2Name" | ||||
|           name="name" | ||||
|           value={formData.test2.name} | ||||
|           onChange={handleTest2Change} | ||||
|         /> | ||||
|       </div> | ||||
|       <div> | ||||
|         <label htmlFor="test2Description">Description:</label> | ||||
|         <input | ||||
|           type="text" | ||||
|           id="test2Description" | ||||
|           name="description" | ||||
|           value={formData.test2.description} | ||||
|           onChange={handleTest2Change} | ||||
|         /> | ||||
|       </div> | ||||
|       <button type="submit">Submit</button> | ||||
|     </form> | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| export default MyForm; | ||||
|  | ||||
| @ -1,100 +1,100 @@ | ||||
| /* sidebar.css */ | ||||
| 
 | ||||
| /* Common styles */ | ||||
| .sidebar { | ||||
|   width: 250px; /* Initial width */ | ||||
|   height: 100%; | ||||
|   background-color: #778184; | ||||
|   color: #0e0e0e; | ||||
|   overflow-y: auto; | ||||
|   transition: width 0.3s; | ||||
| } | ||||
| 
 | ||||
| .sidebar.collapsed { | ||||
|   width: 60px; /* Collapsed width */ | ||||
| } | ||||
| 
 | ||||
| .sidebar .navbar { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: space-between; | ||||
|   padding: 20px; | ||||
|   background-color: #5f6265; | ||||
| } | ||||
| 
 | ||||
| .sidebar .navbar button { | ||||
|   background: none; | ||||
|   border: none; | ||||
|   font-size: 1.5em; | ||||
|   color: #fff; | ||||
|   cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| .sidebar ul { | ||||
|   list-style: none; | ||||
|   padding: 0; | ||||
|   margin: 0; | ||||
| } | ||||
| 
 | ||||
| .sidebar li { | ||||
|   padding: 10px; | ||||
|   cursor: pointer; | ||||
|   transition: background-color 0.3s; | ||||
| } | ||||
| 
 | ||||
| .sidebar li:hover { | ||||
|   background-color: #555; | ||||
| } | ||||
| 
 | ||||
| /* Responsive styles */ | ||||
| @media (max-width: 768px) { | ||||
|   .sidebar { | ||||
|     width: 60px; /* Collapsed width for smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar.collapsed { | ||||
|     width: 60px; /* Ensure sidebar stays collapsed on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar .navbar h2 { | ||||
|     display: none; /* Hide the sidebar title on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar .navbar button { | ||||
|     font-size: 1.2em; /* Reduce button size on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar li { | ||||
|     padding: 8px; /* Reduce padding for menu items on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar ul { | ||||
|     padding-left: 0; /* Remove left padding for nested UL on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar li div { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|   } | ||||
| 
 | ||||
|   .sidebar li div svg { | ||||
|     display: none; /* Hide submenu toggle icons on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar li div .submenu-icon { | ||||
|     display: inline-block; /* Show submenu toggle icon as inline-block */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar li div .submenu-icon svg { | ||||
|     margin-left: 5px; /* Add margin to submenu toggle icon */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar ul ul { | ||||
|     display: none; /* Hide submenus by default on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar ul ul.active { | ||||
|     display: block; /* Show active submenus on smaller screens */ | ||||
|   } | ||||
| } | ||||
| /* sidebar.css */ | ||||
| 
 | ||||
| /* Common styles */ | ||||
| .sidebar { | ||||
|   width: 250px; /* Initial width */ | ||||
|   height: 100%; | ||||
|   background-color: #778184; | ||||
|   color: #0e0e0e; | ||||
|   overflow-y: auto; | ||||
|   transition: width 0.3s; | ||||
| } | ||||
| 
 | ||||
| .sidebar.collapsed { | ||||
|   width: 60px; /* Collapsed width */ | ||||
| } | ||||
| 
 | ||||
| .sidebar .navbar { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: space-between; | ||||
|   padding: 20px; | ||||
|   background-color: #5f6265; | ||||
| } | ||||
| 
 | ||||
| .sidebar .navbar button { | ||||
|   background: none; | ||||
|   border: none; | ||||
|   font-size: 1.5em; | ||||
|   color: #fff; | ||||
|   cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| .sidebar ul { | ||||
|   list-style: none; | ||||
|   padding: 0; | ||||
|   margin: 0; | ||||
| } | ||||
| 
 | ||||
| .sidebar li { | ||||
|   padding: 10px; | ||||
|   cursor: pointer; | ||||
|   transition: background-color 0.3s; | ||||
| } | ||||
| 
 | ||||
| .sidebar li:hover { | ||||
|   background-color: #555; | ||||
| } | ||||
| 
 | ||||
| /* Responsive styles */ | ||||
| @media (max-width: 768px) { | ||||
|   .sidebar { | ||||
|     width: 60px; /* Collapsed width for smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar.collapsed { | ||||
|     width: 60px; /* Ensure sidebar stays collapsed on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar .navbar h2 { | ||||
|     display: none; /* Hide the sidebar title on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar .navbar button { | ||||
|     font-size: 1.2em; /* Reduce button size on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar li { | ||||
|     padding: 8px; /* Reduce padding for menu items on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar ul { | ||||
|     padding-left: 0; /* Remove left padding for nested UL on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar li div { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|   } | ||||
| 
 | ||||
|   .sidebar li div svg { | ||||
|     display: none; /* Hide submenu toggle icons on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar li div .submenu-icon { | ||||
|     display: inline-block; /* Show submenu toggle icon as inline-block */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar li div .submenu-icon svg { | ||||
|     margin-left: 5px; /* Add margin to submenu toggle icon */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar ul ul { | ||||
|     display: none; /* Hide submenus by default on smaller screens */ | ||||
|   } | ||||
| 
 | ||||
|   .sidebar ul ul.active { | ||||
|     display: block; /* Show active submenus on smaller screens */ | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,80 +1,119 @@ | ||||
| import React, { useState } from 'react'; | ||||
| import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||||
| import { | ||||
|   faAngleRight, faAngleDown, faUser, faUsers, faList, faLock, faCog, faFileAlt, faBook, faPen, faExchangeAlt, faUserShield, | ||||
| } from '@fortawesome/free-solid-svg-icons'; | ||||
| import './sidebar.css'; | ||||
| 
 | ||||
| const Sidebar = ({ menus, handleMenuItemClick }) => { | ||||
|   const [collapsed, setCollapsed] = useState(true); | ||||
| 
 | ||||
|   // Initialize collapsedSubmenus state
 | ||||
|   const [collapsedSubmenus, setCollapsedSubmenus] = useState( | ||||
|     menus.reduce((acc, menu) => { | ||||
|       acc[menu.moduleName] = true; | ||||
|       return acc; | ||||
|     }, {}) | ||||
|   ); | ||||
| 
 | ||||
|   const handleSubmenuClick = (menuName) => { | ||||
|     setCollapsedSubmenus((prevCollapsedSubmenus) => ({ | ||||
|       ...prevCollapsedSubmenus, | ||||
|       [menuName]: !prevCollapsedSubmenus[menuName], | ||||
|     })); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className={`flex flex-col h-full ${collapsed ? 'w-16' : 'w-64'} bg-gray-800 text-white transition-all duration-300`}> | ||||
|       <div className="flex items-center justify-between p-4 bg-gray-900"> | ||||
|         <button onClick={() => setCollapsed(!collapsed)}> | ||||
|           <FontAwesomeIcon icon={collapsed ? faAngleRight : faAngleDown} /> | ||||
|         </button> | ||||
|         {!collapsed && <h2 className="ml-2">Cloudnsure</h2>} | ||||
|       </div> | ||||
|       <ul className="flex-1 overflow-y-auto"> | ||||
|         {menus.map((menu) => ( | ||||
|           <li key={menu.moduleName} className="group"> | ||||
|             <div | ||||
|               onClick={() => handleSubmenuClick(menu.moduleName)} | ||||
|               className="flex items-center p-4 cursor-pointer hover:bg-gray-700" | ||||
|             > | ||||
|               {/* Manually adding icons for specific menus */} | ||||
|               {menu.moduleName === 'dashboard' && <FontAwesomeIcon icon={faPen} className="mr-2" />} | ||||
|               {menu.moduleName === 'sec3000' && <FontAwesomeIcon icon={faLock} className="mr-2" />} | ||||
|               {menu.moduleName === 'Super Admin' && <FontAwesomeIcon icon={faUserShield} className="mr-2" />} | ||||
|               {menu.moduleName === 'Transaction' && <FontAwesomeIcon icon={faExchangeAlt} className="mr-2" />} | ||||
|               {/* Display menu name */} | ||||
|               <span className={`flex-1 ${collapsed ? 'hidden' : 'block'}`}>{menu.moduleName}</span> | ||||
|               {/* Submenu toggle icon */} | ||||
|               <FontAwesomeIcon icon={collapsedSubmenus[menu.moduleName] ? faAngleRight : faAngleDown} /> | ||||
|             </div> | ||||
|             {!collapsedSubmenus[menu.moduleName] && ( | ||||
|               <ul className={`pl-8 ${collapsed ? 'hidden' : 'block'}`}> | ||||
|                 {menu.subMenus.map((submenu, index) => ( | ||||
|                   <li | ||||
|                     key={index} | ||||
|                     onClick={() => handleMenuItemClick(submenu)} | ||||
|                     className="flex items-center p-2 cursor-pointer hover:bg-gray-600" | ||||
|                   > | ||||
|                     {/* Manually adding icons for specific submenus */} | ||||
|                     {submenu.menuItemDesc === 'User Maintance' && <FontAwesomeIcon icon={faUser} className="mr-2" />} | ||||
|                     {submenu.menuItemDesc === 'User Group Maintance' && <FontAwesomeIcon icon={faUsers} className="mr-2" />} | ||||
|                     {submenu.menuItemDesc === 'Menu Maintance' && <FontAwesomeIcon icon={faList} className="mr-2" />} | ||||
|                     {submenu.menuItemDesc === 'Menu Access Control' && <FontAwesomeIcon icon={faLock} className="mr-2" />} | ||||
|                     {submenu.menuItemDesc === 'System Parameters' && <FontAwesomeIcon icon={faCog} className="mr-2" />} | ||||
|                     {submenu.menuItemDesc === 'Access Type' && <FontAwesomeIcon icon={faFileAlt} className="mr-2" />} | ||||
|                     {submenu.menuItemDesc === 'Document Sequence' && <FontAwesomeIcon icon={faBook} className="mr-2" />} | ||||
|                     {/* Display submenu name */} | ||||
|                     {submenu.menuItemDesc} | ||||
|                   </li> | ||||
|                 ))} | ||||
|               </ul> | ||||
|             )} | ||||
|           </li> | ||||
|         ))} | ||||
|       </ul> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default Sidebar; | ||||
| import React, { useEffect, useState } from "react"; | ||||
| import { FiChevronRight, FiChevronDown, FiSettings } from "react-icons/fi"; | ||||
| import { Link } from "react-router-dom"; | ||||
| import { FaChevronRight as FaChevronRightIcon } from "react-icons/fa"; | ||||
| 
 | ||||
| const Sidebar = ({ menus, handleMenuItemClick, collapsed }) => { | ||||
|   const [isOpen, setIsOpen] = useState(true); | ||||
|   const [openSubmenu, setOpenSubmenu] = useState(null); | ||||
|   const [menuItems, setMenuItems] = useState([]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchMenuItems = async () => { | ||||
|       const token = localStorage.getItem("authToken"); | ||||
|       try { | ||||
|         const res = await fetch( | ||||
|           `${process.env.REACT_APP_API_BASE_URL}/fndMenu/menuloadbyuser`, | ||||
|           { | ||||
|             headers: { | ||||
|               Authorization: `Bearer ${token}`, | ||||
|             }, | ||||
|           } | ||||
|         ); | ||||
|         const data = await res.json(); | ||||
|         setMenuItems(data); | ||||
|         console.log("Fetched Menu Data:", data); | ||||
|       } catch (error) { | ||||
|         console.error("Error fetching menu items:", error); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     fetchMenuItems(); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleToggle = () => setIsOpen(!isOpen); | ||||
|   const handleSubmenuToggle = (menu) => { | ||||
|     setOpenSubmenu(openSubmenu === menu ? null : menu); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div | ||||
|       className={`flex flex-col h-screen bg-gray-100 text-black ${isOpen ? "w-64" : "w-20" | ||||
|         } transition-all duration-300`}
 | ||||
|     > | ||||
|       <div className="flex items-center justify-between p-4"> | ||||
|         {isOpen ? ( | ||||
|           <span className="text-lg font-bold">Menu</span> | ||||
|         ) : ( | ||||
|           <FiSettings | ||||
|             className="text-2xl cursor-pointer" | ||||
|             onClick={handleToggle} | ||||
|           /> | ||||
|         )} | ||||
|         <button onClick={handleToggle}> | ||||
|           <svg | ||||
|             className="w-6 h-6" | ||||
|             fill="none" | ||||
|             stroke="currentColor" | ||||
|             viewBox="0 0 24 24" | ||||
|             xmlns="http://www.w3.org/2000/svg" | ||||
|           > | ||||
|             <path | ||||
|               strokeLinecap="round" | ||||
|               strokeLinejoin="round" | ||||
|               strokeWidth="2" | ||||
|               d="M4 6h16M4 12h16m-7 6h7" | ||||
|             ></path> | ||||
|           </svg> | ||||
|         </button> | ||||
|       </div> | ||||
|       {isOpen && ( | ||||
|         <nav className="flex flex-col mt-4"> | ||||
|           {menuItems.map((item) => ( | ||||
|             <div key={item.id} className="relative"> | ||||
|               <button | ||||
|                 className="flex items-center p-4 hover:bg-gray-300 w-full text-left" | ||||
|                 onClick={() => handleSubmenuToggle(item.id)} | ||||
|               > | ||||
|                 {item.icon && <item.icon className="w-6 h-6 mr-2" />} | ||||
|                 <span>{item.menuItemDesc}</span> | ||||
|                 {!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 { useNavigate } from 'react-router-dom'; | ||||
| import { AccountCircle, Visibility, VisibilityOff } from '@mui/icons-material'; | ||||
| import './Login.css'; // Import CSS file for custom styling
 | ||||
| 
 | ||||
| const CreateAccountPage = () => { | ||||
|   const [email, setEmail] = useState(''); | ||||
|   const [password, setPassword] = useState(''); | ||||
|   const [reEnterPassword, setReEnterPassword] = useState(''); | ||||
|   const [avatarImage, setAvatarImage] = useState(null); | ||||
|   const navigate = useNavigate(); | ||||
| 
 | ||||
|   const handleCreateAccount = (e) => { | ||||
|     e.preventDefault(); | ||||
|     // Your create account logic here
 | ||||
|   }; | ||||
| 
 | ||||
|   const handleAvatarChange = (e) => { | ||||
|     const file = e.target.files[0]; | ||||
|     if (file) { | ||||
|       const reader = new FileReader(); | ||||
|       reader.onload = () => { | ||||
|         setAvatarImage(reader.result); | ||||
|       }; | ||||
|       reader.readAsDataURL(file); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="relative min-h-screen flex items-center justify-center bg-gray-800"> | ||||
|       <div className="absolute inset-0 flex items-center justify-center"> | ||||
|         <div className="text-center text-gray-200 text-9xl font-bold opacity-10"> | ||||
|           CLOUDNSURE | ||||
|         </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"> | ||||
|           <AccountCircle className="text-7xl text-gray-700" /> | ||||
|         </div> | ||||
|         <h2 className="text-2xl font-semibold text-center text-gray-800 mb-4">Create Account</h2> | ||||
|         <form onSubmit={handleCreateAccount} className="space-y-4"> | ||||
|           <div className="flex items-center justify-center"> | ||||
|             <input | ||||
|               accept="image/*" | ||||
|               id="avatar-input" | ||||
|               type="file" | ||||
|               className="hidden" | ||||
|               onChange={handleAvatarChange} | ||||
|             /> | ||||
|             <label htmlFor="avatar-input" className="cursor-pointer"> | ||||
|               <img | ||||
|                 alt="Avatar" | ||||
|                 src={avatarImage || 'https://via.placeholder.com/120'} | ||||
|                 className="w-28 h-28 rounded-full mb-4" | ||||
|               /> | ||||
|             </label> | ||||
|           </div> | ||||
|           <div> | ||||
|             <label className="block text-gray-600">Email</label> | ||||
|             <input | ||||
|               type="email" | ||||
|               value={email} | ||||
|               onChange={(e) => setEmail(e.target.value)} | ||||
|               className="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring focus:ring-opacity-50" | ||||
|             /> | ||||
|           </div> | ||||
|           <div> | ||||
|             <label className="block text-gray-600">Password</label> | ||||
|             <input | ||||
|               type="password" | ||||
|               value={password} | ||||
|               onChange={(e) => setPassword(e.target.value)} | ||||
|               className="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring focus:ring-opacity-50" | ||||
|             /> | ||||
|           </div> | ||||
|           <div> | ||||
|             <label className="block text-gray-600">Re-enter Password</label> | ||||
|             <input | ||||
|               type="password" | ||||
|               value={reEnterPassword} | ||||
|               onChange={(e) => setReEnterPassword(e.target.value)} | ||||
|               className="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring focus:ring-opacity-50" | ||||
|             /> | ||||
|           </div> | ||||
|           <div className="text-center"> | ||||
|             <button | ||||
|               type="submit" | ||||
|               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" | ||||
|             > | ||||
|               Create Account | ||||
|             </button> | ||||
|           </div> | ||||
|         </form> | ||||
|         <div className="mt-4 text-center"> | ||||
|           <p className="text-gray-600"> | ||||
|             Already have an account?{' '} | ||||
|             <button | ||||
|               type="button" | ||||
|               onClick={() => navigate('/login')} | ||||
|               className="text-blue-600 hover:underline focus:outline-none" | ||||
|             > | ||||
|               Log in | ||||
|             </button> | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default CreateAccountPage; | ||||
| import React, { useState, useEffect } from 'react'; | ||||
| import { Eye, EyeOff, User, Lock, Mail, Camera, UserPlus, ArrowLeft, Check } from 'lucide-react'; | ||||
| 
 | ||||
| // Mock navigation function for demo
 | ||||
| const mockNavigate = (path) => { | ||||
|   console.log(`Navigating to: ${path}`); | ||||
|   alert(`Would navigate to: ${path}`); | ||||
| }; | ||||
| 
 | ||||
| const CreateAccountPage = () => { | ||||
|   const [email, setEmail] = useState(''); | ||||
|   const [password, setPassword] = useState(''); | ||||
|   const [reEnterPassword, setReEnterPassword] = useState(''); | ||||
|   const [avatarImage, setAvatarImage] = useState(null); | ||||
|   const [showPassword, setShowPassword] = useState(false); | ||||
|   const [showReEnterPassword, setShowReEnterPassword] = useState(false); | ||||
|   const [isLoading, setIsLoading] = useState(false); | ||||
|   const [mounted, setMounted] = useState(false); | ||||
|   const [errorMessage, setErrorMessage] = useState(''); | ||||
|   const [passwordStrength, setPasswordStrength] = useState(0); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     setMounted(true); | ||||
|   }, []); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     // Calculate password strength
 | ||||
|     let strength = 0; | ||||
|     if (password.length >= 8) strength++; | ||||
|     if (/[A-Z]/.test(password)) strength++; | ||||
|     if (/[0-9]/.test(password)) strength++; | ||||
|     if (/[^A-Za-z0-9]/.test(password)) strength++; | ||||
|     setPasswordStrength(strength); | ||||
|   }, [password]); | ||||
| 
 | ||||
|   const handleCreateAccount = async (e) => { | ||||
|     e.preventDefault(); | ||||
|     setErrorMessage(''); | ||||
|     setIsLoading(true); | ||||
| 
 | ||||
|     if (!email || !password || !reEnterPassword) { | ||||
|       setErrorMessage('All fields are required.'); | ||||
|       setIsLoading(false); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     if (password !== reEnterPassword) { | ||||
|       setErrorMessage('Passwords do not match.'); | ||||
|       setIsLoading(false); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     if (password.length < 8) { | ||||
|       setErrorMessage('Password must be at least 8 characters long.'); | ||||
|       setIsLoading(false); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     // Simulate API call
 | ||||
|     setTimeout(() => { | ||||
|       console.log('Account created successfully!'); | ||||
|       alert('Account created successfully!'); | ||||
|       mockNavigate('/login'); | ||||
|       setIsLoading(false); | ||||
|     }, 2000); | ||||
|   }; | ||||
| 
 | ||||
|   const handleAvatarChange = (e) => { | ||||
|     const file = e.target.files[0]; | ||||
|     if (file) { | ||||
|       const reader = new FileReader(); | ||||
|       reader.onload = () => { | ||||
|         setAvatarImage(reader.result); | ||||
|       }; | ||||
|       reader.readAsDataURL(file); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const getPasswordStrengthColor = () => { | ||||
|     if (passwordStrength === 0) return 'bg-gray-300'; | ||||
|     if (passwordStrength === 1) return 'bg-red-400'; | ||||
|     if (passwordStrength === 2) return 'bg-yellow-400'; | ||||
|     if (passwordStrength === 3) return 'bg-blue-400'; | ||||
|     return 'bg-green-400'; | ||||
|   }; | ||||
| 
 | ||||
|   const getPasswordStrengthText = () => { | ||||
|     if (passwordStrength === 0) return 'Enter password'; | ||||
|     if (passwordStrength === 1) return 'Weak'; | ||||
|     if (passwordStrength === 2) return 'Fair'; | ||||
|     if (passwordStrength === 3) return 'Good'; | ||||
|     return 'Strong'; | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="min-h-screen bg-gradient-to-br from-purple-50 via-white to-purple-100 relative overflow-hidden"> | ||||
|       {/* Background Elements */} | ||||
|       <div className="absolute inset-0"> | ||||
|         {/* Subtle geometric shapes */} | ||||
|         <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> | ||||
|         <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> | ||||
|          | ||||
|         {/* Grid pattern */} | ||||
|         <div className="absolute inset-0 opacity-5" style={{ | ||||
|           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> | ||||
| 
 | ||||
|       {/* Main Content */} | ||||
|       <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 { useNavigate } from 'react-router-dom'; | ||||
| import { AccountCircle } from '@mui/icons-material'; | ||||
| import './Login.css'; // Import CSS file for custom styling
 | ||||
| 
 | ||||
| const API_BASE_URL = process.env.REACT_APP_API_BASE_URL; | ||||
| const API_FORGOT_PASSWORD = `${API_BASE_URL}/backend/api/resources/forgotpassword`; | ||||
| 
 | ||||
| const ForgotPasswordPage = () => { | ||||
|   const [email, setEmail] = useState(''); | ||||
|   const [message, setMessage] = useState(''); | ||||
|   const [messageType, setMessageType] = useState(''); // State to manage message type for styling
 | ||||
|   const navigate = useNavigate(); | ||||
| 
 | ||||
|   const handleSubmit = async (e) => { | ||||
|     e.preventDefault(); | ||||
| 
 | ||||
|     try { | ||||
|       const response = await fetch(API_FORGOT_PASSWORD, { | ||||
|         method: 'POST', | ||||
|         headers: { | ||||
|           'Content-Type': 'application/json', | ||||
|         }, | ||||
|         body: JSON.stringify({ email }), | ||||
|       }); | ||||
| 
 | ||||
|       if (!response.ok) { | ||||
|         const errorText = await response.text(); | ||||
|         setMessage(`Reset password failed: ${errorText}`); | ||||
|         setMessageType('error'); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       setMessage('Reset password email sent successfully. Please check your email.'); | ||||
|       setMessageType('success'); | ||||
|     } catch (error) { | ||||
|       setMessage(`Error during reset password: ${error.message}`); | ||||
|       setMessageType('error'); | ||||
|       console.error('Error during reset password:', error); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="relative min-h-screen flex items-center justify-center bg-gray-800"> | ||||
|       <div className="absolute inset-0 flex items-center justify-center"> | ||||
|         <div className="text-center text-gray-200 text-9xl font-bold opacity-10"> | ||||
|           CLOUDNSURE | ||||
|         </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"> | ||||
|           <AccountCircle className="text-7xl text-gray-700" /> | ||||
|         </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"> | ||||
|           Enter your email address and we'll send you a link to reset your password. | ||||
|         </p> | ||||
|         <form onSubmit={handleSubmit} className="space-y-4"> | ||||
|           <div> | ||||
|             <label className="block text-gray-600">Email</label> | ||||
|             <input | ||||
|               type="email" | ||||
|               value={email} | ||||
|               onChange={(e) => setEmail(e.target.value)} | ||||
|               className="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring focus:ring-opacity-50" | ||||
|               required | ||||
|               autoFocus | ||||
|             /> | ||||
|           </div> | ||||
|           <div className="text-center"> | ||||
|             <button | ||||
|               type="submit" | ||||
|               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> | ||||
|         </form> | ||||
|         {message && ( | ||||
|           <div className={`mt-4 text-center ${messageType === 'error' ? 'text-red-500' : 'text-green-500'}`}> | ||||
|             {message} | ||||
|           </div> | ||||
|         )} | ||||
|         <p className="mt-4 text-center text-gray-600"> | ||||
|           Remember your password?{' '} | ||||
|           <button | ||||
|             type="button" | ||||
|             onClick={() => navigate('/login')} | ||||
|             className="text-blue-600 hover:underline focus:outline-none" | ||||
|           > | ||||
|             Log in | ||||
|           </button> | ||||
|         </p> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default ForgotPasswordPage; | ||||
| import React, { useState, useEffect } from 'react'; | ||||
| import { Mail, ArrowLeft, Shield, CheckCircle, AlertCircle, Sparkles } from 'lucide-react'; | ||||
| 
 | ||||
| const ForgotPasswordPage = () => { | ||||
|   const [email, setEmail] = useState(''); | ||||
|   const [message, setMessage] = useState(''); | ||||
|   const [messageType, setMessageType] = useState(''); | ||||
|   const [isLoading, setIsLoading] = useState(false); | ||||
|   const [mounted, setMounted] = useState(false); | ||||
|   const [particles, setParticles] = useState([]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     setMounted(true); | ||||
|      | ||||
|     const newParticles = Array.from({ length: 35 }, (_, i) => ({ | ||||
|       id: i, | ||||
|       x: Math.random() * 100, | ||||
|       y: Math.random() * 100, | ||||
|       size: Math.random() * 3 + 1, | ||||
|       duration: Math.random() * 4 + 3, | ||||
|       delay: Math.random() * 2, | ||||
|     })); | ||||
|     setParticles(newParticles); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleSubmit = async (e) => { | ||||
|     e.preventDefault(); | ||||
|     setIsLoading(true); | ||||
|     setMessage(''); | ||||
|     setMessageType(''); | ||||
| 
 | ||||
|     try { | ||||
|       await new Promise(resolve => setTimeout(resolve, 2000)); | ||||
|        | ||||
|       if (email.includes('@')) { | ||||
|         setMessage('Reset password email sent successfully. Please check your email.'); | ||||
|         setMessageType('success'); | ||||
|         setEmail(''); | ||||
|       } else { | ||||
|         setMessage('Please enter a valid email address.'); | ||||
|         setMessageType('error'); | ||||
|       } | ||||
|     } catch (error) { | ||||
|       setMessage(`Error during reset password: ${error.message}`); | ||||
|       setMessageType('error'); | ||||
|     } finally { | ||||
|       setIsLoading(false); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleBackToLogin = () => { | ||||
|     alert('Back to login functionality would be implemented here'); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="min-h-screen relative overflow-hidden bg-gradient-to-br from-gray-50 via-white to-purple-50"> | ||||
|       <div className="absolute inset-0"> | ||||
|         <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> | ||||
|          | ||||
|         {particles.map((particle) => ( | ||||
|           <div | ||||
|             key={particle.id} | ||||
|             className="absolute bg-purple-400 rounded-full opacity-20 animate-bounce" | ||||
|             style={{ | ||||
|               left: `${particle.x}%`, | ||||
|               top: `${particle.y}%`, | ||||
|               width: `${particle.size}px`, | ||||
|               height: `${particle.size}px`, | ||||
|               animationDuration: `${particle.duration}s`, | ||||
|               animationDelay: `${particle.delay}s`, | ||||
|             }} | ||||
|           /> | ||||
|         ))} | ||||
|          | ||||
|         <div className="absolute inset-0 opacity-20" style={{ | ||||
|           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")` | ||||
|         }}></div> | ||||
|       </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"> | ||||
|           <div className={`text-center transition-all duration-2000 ${mounted ? 'opacity-5 scale-100' : 'opacity-0 scale-95'}`}> | ||||
|             <div className="flex justify-center mt-4 space-x-2"> | ||||
|               {[...Array(5)].map((_, i) => ( | ||||
|                 <Sparkles key={i} className="w-8 h-8 text-purple-300 opacity-30 animate-pulse" style={{ animationDelay: `${i * 0.3}s` }} /> | ||||
|               ))} | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div className={`relative w-full max-w-md transition-all duration-1000 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}> | ||||
|           <div className="relative bg-white rounded-3xl shadow-2xl border border-purple-100 overflow-hidden"> | ||||
|             <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 | ||||
|                 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 */ | ||||
| 
 | ||||
| .login-container { | ||||
|   background: linear-gradient(to bottom, #417cd5, white); /* Linear gradient from blue to white */ | ||||
|   height: 100vh; /* Full viewport height */ | ||||
|   display: flex; | ||||
| } | ||||
| 
 | ||||
|    | ||||
|   .login-box { | ||||
|     display: flex; | ||||
|     background-color: white; | ||||
|     box-shadow: 0 4px 8px rgba(0,0,0,0.1); | ||||
|     border-radius: 8px; | ||||
|     overflow: hidden; | ||||
|     height: 500px; | ||||
|   } | ||||
|    | ||||
|   .login-left { | ||||
|     background-color: #31c2db; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     flex: 1; | ||||
|     padding: 4rem; /* Padding for better spacing */ | ||||
| } | ||||
|    | ||||
|   .login-left img { | ||||
|     width: 80px; | ||||
|   } | ||||
|    | ||||
|   .login-right { | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     flex: 1; | ||||
|     padding: 4rem; /* Padding for better spacing */ | ||||
| } | ||||
|    | ||||
| .login-form { | ||||
|   width: 100%; | ||||
|   max-width: 400px; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
| } | ||||
| .forgot-password, .create-account { | ||||
|   margin-top: 1rem; /* Spacing between links and other elements */ | ||||
| } | ||||
| 
 | ||||
| .login-form .MuiButton-root { | ||||
|   background-color: #1fcf90; | ||||
|   color: white; | ||||
|   margin-top: 1rem; /* Spacing at the top of the button */ | ||||
| } | ||||
| 
 | ||||
| .MuiAlert-root { | ||||
|   margin-bottom: 1rem; /* Spacing below the alert */ | ||||
| } | ||||
|   .forgot-password { | ||||
|     text-align: right; | ||||
|     margin-top: -10px; | ||||
|   } | ||||
| /* LoginPage.css */ | ||||
| 
 | ||||
| .login-container { | ||||
|   background: linear-gradient(to bottom, #417cd5, white); /* Linear gradient from blue to white */ | ||||
|   height: 100vh; /* Full viewport height */ | ||||
|   display: flex; | ||||
| } | ||||
| 
 | ||||
|    | ||||
|   .login-box { | ||||
|     display: flex; | ||||
|     background-color: white; | ||||
|     box-shadow: 0 4px 8px rgba(0,0,0,0.1); | ||||
|     border-radius: 8px; | ||||
|     overflow: hidden; | ||||
|     height: 500px; | ||||
|   } | ||||
|    | ||||
|   .login-left { | ||||
|     background-color: #31c2db; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     flex: 1; | ||||
|     padding: 4rem; /* Padding for better spacing */ | ||||
| } | ||||
|    | ||||
|   .login-left img { | ||||
|     width: 80px; | ||||
|   } | ||||
|    | ||||
|   .login-right { | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     flex: 1; | ||||
|     padding: 4rem; /* Padding for better spacing */ | ||||
| } | ||||
|    | ||||
| .login-form { | ||||
|   width: 100%; | ||||
|   max-width: 400px; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
| } | ||||
| .forgot-password, .create-account { | ||||
|   margin-top: 1rem; /* Spacing between links and other elements */ | ||||
| } | ||||
| 
 | ||||
| .login-form .MuiButton-root { | ||||
|   background-color: #1fcf90; | ||||
|   color: white; | ||||
|   margin-top: 1rem; /* Spacing at the top of the button */ | ||||
| } | ||||
| 
 | ||||
| .MuiAlert-root { | ||||
|   margin-bottom: 1rem; /* Spacing below the alert */ | ||||
| } | ||||
|   .forgot-password { | ||||
|     text-align: right; | ||||
|     margin-top: -10px; | ||||
|   } | ||||
|    | ||||
| @ -1,156 +1,238 @@ | ||||
| import React, { useState } from 'react'; | ||||
| import { useNavigate } from 'react-router-dom'; | ||||
| import { AccountCircle, Visibility, VisibilityOff } from '@mui/icons-material'; | ||||
| import './Login.css'; // Import CSS file for custom styling
 | ||||
| 
 | ||||
| const API_BASE_URL = process.env.REACT_APP_API_BASE_URL; | ||||
| const API_TOKEN_SESSION = `${API_BASE_URL}/token/session`; | ||||
| 
 | ||||
| const LoginPage = () => { | ||||
|   const [email, setEmail] = useState(''); | ||||
|   const [password, setPassword] = useState(''); | ||||
|   const [showPassword, setShowPassword] = useState(false); | ||||
|   const [rememberMe, setRememberMe] = useState(false); | ||||
|   const [errorMessage, setErrorMessage] = useState(''); | ||||
|   const navigate = useNavigate(); | ||||
| 
 | ||||
|   const handleLogin = async (e) => { | ||||
|     e.preventDefault(); | ||||
|     setErrorMessage(''); | ||||
| 
 | ||||
|     if (!email || !password) { | ||||
|       setErrorMessage('Email and password are required.'); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     try { | ||||
|       const response = await fetch(API_TOKEN_SESSION, { | ||||
|         method: 'POST', | ||||
|         headers: { | ||||
|           'Content-Type': 'application/json', | ||||
|         }, | ||||
|         body: JSON.stringify({ email, password }), | ||||
|       }); | ||||
| 
 | ||||
|       if (!response.ok) { | ||||
|         const errorText = await response.text(); | ||||
|         console.error('Login failed:', errorText); | ||||
|         setErrorMessage('Login failed. Please check your credentials.'); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       const data = await response.json(); | ||||
|       console.log('Login response:', data); | ||||
| 
 | ||||
|       if (data.operationStatus !== 'SUCCESS') { | ||||
|         console.error('Login failed:', data.operationMessage); | ||||
|         setErrorMessage(data.operationMessage || 'Login failed. Please try again.'); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       localStorage.setItem('authToken', data.item.token); | ||||
|       localStorage.setItem('user', JSON.stringify(data.item)); | ||||
|       console.log('Token stored in local storage:', data.item.token); | ||||
|       navigate('/dashboard'); | ||||
|     } catch (error) { | ||||
|       console.error('Error during login:', error); | ||||
|       setErrorMessage('An error occurred during login. Please try again later.'); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handleForgotPassword = () => { | ||||
|     navigate('/ForgotPassword'); | ||||
|   }; | ||||
| 
 | ||||
|   const handleCreateAccount = () => { | ||||
|     navigate('/CreateAccount'); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="relative min-h-screen flex items-center justify-center bg-gray-700"> | ||||
|       <div className="absolute inset-0 flex items-center justify-center"> | ||||
|         <div className="text-center text-gray-100 text-9xl font-bold opacity-75"> | ||||
|           CLOUDNSURE | ||||
|         </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"> | ||||
|           <AccountCircle className="text-7xl text-gray-700" /> | ||||
|         </div> | ||||
|         <h2 className="text-2xl font-semibold text-center text-gray-800 mb-4 ">Log in</h2> | ||||
|         {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 | ||||
|               type="text" | ||||
|               value={email} | ||||
|               onChange={(e) => setEmail(e.target.value)} | ||||
|               className="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring focus:ring-opacity-50" | ||||
|             /> | ||||
|           </div> | ||||
|           <div> | ||||
|             <label className="block text-gray-600">Password</label> | ||||
|             <div className="relative"> | ||||
|               <input | ||||
|                 type={showPassword ? 'text' : 'password'} | ||||
|                 value={password} | ||||
|                 onChange={(e) => setPassword(e.target.value)} | ||||
|                 className="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring focus:ring-opacity-50" | ||||
|               /> | ||||
|               <div className="absolute inset-y-0 right-0 pr-3 flex items-center"> | ||||
|                 <button | ||||
|                   type="button" | ||||
|                   onClick={() => setShowPassword(!showPassword)} | ||||
|                   className="" | ||||
|                 > | ||||
|                   {showPassword ? <VisibilityOff /> : <Visibility />} | ||||
|                 </button> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div className="flex items-center justify-between"> | ||||
|             <label className="flex items-center"> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={rememberMe} | ||||
|                 onChange={(e) => setRememberMe(e.target.checked)} | ||||
|                 className="form-checkbox" | ||||
|               /> | ||||
|               <span className="ml-2 text-gray-600">Remember Me</span> | ||||
|             </label> | ||||
|             <button | ||||
|               type="button" | ||||
|               onClick={handleForgotPassword} | ||||
|               className="text-sm text-blue-600 hover:underline focus:outline-none" | ||||
|             > | ||||
|               Forgot password? | ||||
|             </button> | ||||
|           </div> | ||||
|           <div className="text-center"> | ||||
|             <button | ||||
|               type="submit" | ||||
|               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" | ||||
|             > | ||||
|               Login | ||||
|             </button> | ||||
|           </div> | ||||
|         </form> | ||||
|         <div className="mt-4 text-center"> | ||||
|           <p className="text-gray-600"> | ||||
|             Don't have an account?{' '} | ||||
|             <button | ||||
|               type="button" | ||||
|               onClick={handleCreateAccount} | ||||
|               className="text-blue-600 hover:underline focus:outline-none" | ||||
|             > | ||||
|               Create Account | ||||
|             </button> | ||||
|           </p> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default LoginPage; | ||||
| import React, { useState, useEffect } from 'react'; | ||||
| import { Eye, EyeOff, User, Lock, Mail, Sparkles, Shield, ArrowRight } from 'lucide-react'; | ||||
| import { useNavigate } from 'react-router-dom'; | ||||
| 
 | ||||
| const LoginPage = () => { | ||||
|   const navigate = useNavigate(); | ||||
|   const [username, setUsername] = useState(''); | ||||
|   const [password, setPassword] = useState(''); | ||||
|   const [showPassword, setShowPassword] = useState(false); | ||||
|   const [rememberMe, setRememberMe] = useState(false); | ||||
|   const [errorMessage, setErrorMessage] = useState(''); | ||||
|   const [isLoading, setIsLoading] = useState(false); | ||||
|   const [mounted, setMounted] = useState(false); | ||||
|   const [particles, setParticles] = useState([]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     setMounted(true); | ||||
|      | ||||
|     const newParticles = Array.from({ length: 40 }, (_, i) => ({ | ||||
|       id: i, | ||||
|       x: Math.random() * 100, | ||||
|       y: Math.random() * 100, | ||||
|       size: Math.random() * 3 + 1, | ||||
|       duration: Math.random() * 4 + 3, | ||||
|       delay: Math.random() * 2, | ||||
|     })); | ||||
|     setParticles(newParticles); | ||||
|   }, []); | ||||
| 
 | ||||
|   const handleLogin = async (e) => { | ||||
|     e.preventDefault(); | ||||
|     setErrorMessage(''); | ||||
|     setIsLoading(true); | ||||
| 
 | ||||
|     if (!username || !password) { | ||||
|       setErrorMessage('Username and password are required.'); | ||||
|       setIsLoading(false); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     const storedCredentials = JSON.parse(localStorage.getItem('userCredentials') || '{}'); | ||||
|      | ||||
|     if ((username === 'sysadmin' && password === 'test3') ||  | ||||
|         (storedCredentials[username] && storedCredentials[username] === password)) { | ||||
|       localStorage.setItem('authToken', 'dummy-token'); | ||||
|       localStorage.setItem('currentUser', username); | ||||
|       navigate('/Dashboard'); | ||||
|     } else { | ||||
|       setErrorMessage('Invalid username or password. Please use sysadmin/test3 or your registered credentials.'); | ||||
|     } | ||||
|      | ||||
|     setIsLoading(false); | ||||
|   }; | ||||
| 
 | ||||
|   const handleForgotPassword = () => { | ||||
|     navigate('/ForgotPassword'); | ||||
|   }; | ||||
| 
 | ||||
|   const handleCreateAccount = () => { | ||||
|     navigate('/CreateAccount'); | ||||
|   }; | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="min-h-screen relative overflow-hidden bg-gradient-to-br from-gray-50 via-white to-purple-50"> | ||||
|       <div className="absolute inset-0"> | ||||
|         <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> | ||||
|          | ||||
|         {particles.map((particle) => ( | ||||
|           <div | ||||
|             key={particle.id} | ||||
|             className="absolute bg-purple-400 rounded-full opacity-20 animate-bounce" | ||||
|             style={{ | ||||
|               left: `${particle.x}%`, | ||||
|               top: `${particle.y}%`, | ||||
|               width: `${particle.size}px`, | ||||
|               height: `${particle.size}px`, | ||||
|               animationDuration: `${particle.duration}s`, | ||||
|               animationDelay: `${particle.delay}s`, | ||||
|             }} | ||||
|           /> | ||||
|         ))} | ||||
|          | ||||
|         <div className="absolute inset-0 opacity-20" style={{ | ||||
|           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")` | ||||
|         }}></div> | ||||
|       </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"> | ||||
|           <div className={`text-center transition-all duration-2000 ${mounted ? 'opacity-5 scale-100' : 'opacity-0 scale-95'}`}> | ||||
|             <div className="flex justify-center mt-4 space-x-2"> | ||||
|               {[...Array(5)].map((_, i) => ( | ||||
|                 <Sparkles key={i} className="w-8 h-8 text-purple-300 opacity-30 animate-pulse" style={{ animationDelay: `${i * 0.3}s` }} /> | ||||
|               ))} | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div className={`relative w-full max-w-md transition-all duration-1000 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}> | ||||
|           <div className="relative bg-white rounded-3xl shadow-2xl border border-purple-100 overflow-hidden"> | ||||
|             <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"> | ||||
|               <div className="text-center space-y-4"> | ||||
|                 <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">Welcome Back</h1> | ||||
|                   <p className="text-gray-600">Sign in to your account</p> | ||||
|                 </div> | ||||
|               </div> | ||||
| 
 | ||||
|               {errorMessage && ( | ||||
|                 <div className="bg-red-50 border border-red-200 rounded-xl p-4 text-red-700 text-sm animate-pulse"> | ||||
|                   {errorMessage} | ||||
|                 </div> | ||||
|               )} | ||||
| 
 | ||||
|               <div className="space-y-6"> | ||||
|                 <div className="space-y-2"> | ||||
|                   <label className="text-sm font-medium text-gray-700">Username</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"> | ||||
|                         <User className="w-5 h-5 text-gray-400" /> | ||||
|                       </div> | ||||
|                       <input | ||||
|                         type="text" | ||||
|                         value={username} | ||||
|                         onChange={(e) => setUsername(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 username" | ||||
|                       /> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div className="space-y-2"> | ||||
|                   <label className="text-sm font-medium text-gray-700">Password</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"> | ||||
|                         <Lock className="w-5 h-5 text-gray-400" /> | ||||
|                       </div> | ||||
|                       <input | ||||
|                         type={showPassword ? 'text' : 'password'} | ||||
|                         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" | ||||
|                       /> | ||||
|                       <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', | ||||
|     monospace; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										15
									
								
								src/index.js
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/index.js
									
									
									
									
									
								
							| @ -1,7 +1,6 @@ | ||||
| // index.js
 | ||||
| import React from 'react'; | ||||
| import ReactDOM from 'react-dom'; | ||||
| import { BrowserRouter as Router } from 'react-router-dom'; | ||||
| import { createRoot } from 'react-dom/client'; | ||||
| import { ThemeProvider, createTheme } from '@mui/material/styles'; | ||||
| import App from './App'; | ||||
| import './index.css'; | ||||
| @ -11,13 +10,13 @@ const theme = createTheme({ | ||||
|   // your theme configuration
 | ||||
| }); | ||||
| 
 | ||||
| ReactDOM.render( | ||||
| const container = document.getElementById('root'); | ||||
| const root = createRoot(container); | ||||
| 
 | ||||
| root.render( | ||||
|   <ErrorBoundary> | ||||
|     <ThemeProvider theme={theme}> | ||||
|       <Router> | ||||
|         <App /> | ||||
|       </Router> | ||||
|       <App /> | ||||
|     </ThemeProvider> | ||||
|   </ErrorBoundary>, | ||||
|   document.getElementById('root') | ||||
|   </ErrorBoundary> | ||||
| ); | ||||
|  | ||||
							
								
								
									
										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