Merge pull request 'tf2' (#1) from tf2 into master
Reviewed-on: https://git.humbingo.in/Humbingo/react-placeholder/pulls/1master
|
@ -25,6 +25,7 @@
|
||||||
"react-router-dom": "^6.26.1",
|
"react-router-dom": "^6.26.1",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-toastify": "^10.0.5",
|
"react-toastify": "^10.0.5",
|
||||||
|
"sweetalert2": "^11.12.4",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -18652,6 +18653,16 @@
|
||||||
"boolbase": "~1.0.0"
|
"boolbase": "~1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sweetalert2": {
|
||||||
|
"version": "11.12.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.12.4.tgz",
|
||||||
|
"integrity": "sha512-ZSpyaLbAmn4b7xjnV9x9BFD1UOrCAhIzm1D8dZ443kGxtVKqbTIA5SgXs4xeEtmFfEXUyC3RBgpSlu1AXmCiHA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/limonte"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/symbol-tree": {
|
"node_modules/symbol-tree": {
|
||||||
"version": "3.2.4",
|
"version": "3.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "hbaseapp",
|
"name": "react-placeholder",
|
||||||
"version": "0.1.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.13.0",
|
"@emotion/react": "^11.13.0",
|
||||||
|
@ -20,6 +20,7 @@
|
||||||
"react-router-dom": "^6.26.1",
|
"react-router-dom": "^6.26.1",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-toastify": "^10.0.5",
|
"react-toastify": "^10.0.5",
|
||||||
|
"sweetalert2": "^11.12.4",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
Before Width: | Height: | Size: 3.8 KiB |
|
@ -7,37 +7,16 @@
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Web site created using create-react-app"
|
content=""
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<!--
|
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
|
||||||
-->
|
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
<!--
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
<title>Humbingo React Placeholder</title>
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
|
||||||
Only files inside the `public` folder can be referenced from the HTML.
|
|
||||||
|
|
||||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
|
||||||
work correctly both with client-side routing and a non-root public URL.
|
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
|
||||||
-->
|
|
||||||
<title>React App</title>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<!--
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
|
||||||
This HTML file is a template.
|
|
||||||
If you open it directly in the browser, you will see an empty page.
|
|
||||||
|
|
||||||
You can add webfonts, meta tags, or analytics to this file.
|
|
||||||
The build step will place the bundled scripts into the <body> tag.
|
|
||||||
|
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
|
||||||
-->
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 9.4 KiB |
38
src/App.css
|
@ -1,38 +0,0 @@
|
||||||
.App {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-logo {
|
|
||||||
height: 40vmin;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
.App-logo {
|
|
||||||
animation: App-logo-spin infinite 20s linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-header {
|
|
||||||
background-color: #282c34;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: calc(10px + 2vmin);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-link {
|
|
||||||
color: #61dafb;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes App-logo-spin {
|
|
||||||
from {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
23
src/App.js
|
@ -1,25 +1,28 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LoginPage from './pages/UI/login/login';
|
|
||||||
import { BrowserRouter, Route, Routes } from 'react-router-dom';
|
import { BrowserRouter, Route, Routes } from 'react-router-dom';
|
||||||
import { AuthProvider } from './auth/AuthContext';
|
|
||||||
import { Auth } from './auth/auth';
|
import { AuthProvider } from './utils/auth/AuthContext';
|
||||||
import Footer from './components/footer'; // Import the Footer component
|
import { Auth } from './utils/auth/auth';
|
||||||
import Home from './pages/UI/home/home';
|
import LoginPage from './components/pages/Login';
|
||||||
|
import Home from './components/pages/Home';
|
||||||
|
import APIManagerStarter from './components/pages/APIManagerStarter';
|
||||||
|
import Footer from './components/common/Footer';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
return (
|
return (
|
||||||
<div className='App' style={{ display: 'flex', flexDirection: 'column', minHeight: '100vh' }}>
|
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Auth component={<Home />} />} exact />
|
<Route path="/" element={<Auth component={<Home />} />} exact />
|
||||||
|
<Route path="/login" element={<Auth component={<LoginPage/>} />} exact />
|
||||||
<Route path="/login" element={<Auth component={<LoginPage />} />} exact />
|
<Route path="/api-manager-starter" element={<Auth component={<APIManagerStarter />} />} exact />
|
||||||
</Routes>
|
</Routes>
|
||||||
<Footer />
|
<Footer/>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { render, screen } from '@testing-library/react';
|
|
||||||
import App from './App';
|
|
||||||
|
|
||||||
test('renders learn react link', () => {
|
|
||||||
render(<App />);
|
|
||||||
const linkElement = screen.getByText(/learn react/i);
|
|
||||||
expect(linkElement).toBeInTheDocument();
|
|
||||||
});
|
|
|
@ -1,23 +0,0 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
.env.local
|
|
||||||
.env.development.local
|
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
|
@ -1,416 +0,0 @@
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import { toast } from "react-toastify";
|
|
||||||
import "react-toastify/dist/ReactToastify.css";
|
|
||||||
import Swal from "sweetalert2";
|
|
||||||
import "./style.css";
|
|
||||||
import useAPIManager from "./useAPIManager";
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Table,
|
|
||||||
TableBody,
|
|
||||||
TableCell,
|
|
||||||
TableContainer,
|
|
||||||
TableHead,
|
|
||||||
TableRow,
|
|
||||||
Paper,
|
|
||||||
Menu,
|
|
||||||
MenuItem,
|
|
||||||
Fade,
|
|
||||||
Card,
|
|
||||||
CardContent,
|
|
||||||
} from "@mui/material";
|
|
||||||
import FormWithDrawer from "./FormWithDrawer";
|
|
||||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
|
||||||
import Pagination from "./Pagination";
|
|
||||||
|
|
||||||
function APIManager(props) {
|
|
||||||
const dataSchema = props.data;
|
|
||||||
const { Get, Delete, Patch, getAPI, getHost } = useAPIManager(
|
|
||||||
props.globalConfig,
|
|
||||||
props.token
|
|
||||||
);
|
|
||||||
const dataApi = getAPI(props.data.api);
|
|
||||||
const [apiData, setApiData] = useState([]);
|
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
|
||||||
const [orderBy, setOrderBy] = useState(""); // Column to sort
|
|
||||||
const [order, setOrder] = useState("asc");
|
|
||||||
const [page, setPage] = useState(0);
|
|
||||||
const [rowsPerPage, setRowsPerPage] = useState(50);
|
|
||||||
const [sortedColumn, setSortedColumn] = useState(null);
|
|
||||||
const [filteredData, setFilteredData] = useState([]);
|
|
||||||
const [anchorEls, setAnchorEls] = useState({}); // Updated state for menu anchors
|
|
||||||
const [mounted, setMounted] = useState(false);
|
|
||||||
const [nextPage, setNextPage] = useState(null);
|
|
||||||
const [previousPage, setPreviousPage] = useState(null);
|
|
||||||
const [totalCount, setTotalCount] = useState(0);
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
|
|
||||||
const updateFormTitle = props.updateFormTitle ? props.updateFormTitle : "";
|
|
||||||
const createFormTitle = props.createFormTitle ? props.createFormTitle : "";
|
|
||||||
const actionBtnName = props.actionBtnName
|
|
||||||
? props.actionBtnName
|
|
||||||
: "Create New Data";
|
|
||||||
const createRequired = props.createRequired === false ? false : true;
|
|
||||||
const editRequired = props.editRequired === false ? false : true;
|
|
||||||
const searchRequired = props.searchRequired === false ? false : true;
|
|
||||||
|
|
||||||
const createField = dataSchema.createField;
|
|
||||||
const editField = dataSchema.editField;
|
|
||||||
const showField = dataSchema.showField;
|
|
||||||
const manageRecord = true;
|
|
||||||
|
|
||||||
let navigate = useNavigate();
|
|
||||||
const getData = async () => {
|
|
||||||
makeApiRequest(dataApi);
|
|
||||||
};
|
|
||||||
|
|
||||||
const makeApiRequest = async (api) => {
|
|
||||||
try {
|
|
||||||
setSearchQuery("");
|
|
||||||
const result = await Get(api ? api : dataApi);
|
|
||||||
setNextPage(result.next);
|
|
||||||
setPreviousPage(result.previous);
|
|
||||||
setTotalCount(result.count);
|
|
||||||
setApiData(result.results);
|
|
||||||
setFilteredData(result.results);
|
|
||||||
} catch (err) {
|
|
||||||
if (err.code == "ERR_BAD_REQUEST") {
|
|
||||||
toast.error("Unauthorised access to page, Contact admin for access.");
|
|
||||||
navigate("/");
|
|
||||||
} else {
|
|
||||||
toast.error(err.message);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const pageChangeRequest = (url) => {
|
|
||||||
if (getPageUrl(url) != null) {
|
|
||||||
makeApiRequest(getHost() + getPageUrl(url));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
async function softDelete(data) {
|
|
||||||
try {
|
|
||||||
await Patch(dataApi, data["id"], { is_deleted: true })
|
|
||||||
.then(() => {
|
|
||||||
toast.success("Record updated successfully!");
|
|
||||||
getData();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
getData();
|
|
||||||
toast.error(err || "Error");
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
getData();
|
|
||||||
toast.error("Something Went wrong contact Humbingo");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function restore(data) {
|
|
||||||
try {
|
|
||||||
await Patch(dataApi, data["id"], { is_deleted: false })
|
|
||||||
.then(() => {
|
|
||||||
toast.success("Record updated successfully!");
|
|
||||||
getData();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
getData();
|
|
||||||
toast.error(err || "Error");
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
getData();
|
|
||||||
toast.error("Something Went wrong contact Humbingo");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function forceDelete(data) {
|
|
||||||
await Swal.fire({
|
|
||||||
title: "Data will be removed permanently! Are you sure?",
|
|
||||||
icon: "warning",
|
|
||||||
showCancelButton: true,
|
|
||||||
confirmButtonColor: "#3085d6",
|
|
||||||
cancelButtonColor: "#d33",
|
|
||||||
confirmButtonText: "Yes, delete it!",
|
|
||||||
}).then(async (result) => {
|
|
||||||
if (result.isConfirmed) {
|
|
||||||
try {
|
|
||||||
await Delete(dataApi, data["id"])
|
|
||||||
.then(() => {
|
|
||||||
toast.success("Record updated successfully!");
|
|
||||||
getData();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
getData();
|
|
||||||
toast.error(err || "Error");
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
getData();
|
|
||||||
toast.error("Something Went wrong contact Humbingo");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const getValueFromUrl = (url, parameterName) => {
|
|
||||||
try {
|
|
||||||
const regex = new RegExp(`${parameterName}=([^&]+)`);
|
|
||||||
const match = url.match(regex);
|
|
||||||
return match ? match[1] : null;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function getPageUrl(url) {
|
|
||||||
let urls = "";
|
|
||||||
try {
|
|
||||||
const urlObject = new URL(url);
|
|
||||||
urls = urlObject.pathname + urlObject.search;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return urls;
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMounted(true);
|
|
||||||
return () => {
|
|
||||||
setMounted(false);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (loading && mounted) {
|
|
||||||
getData();
|
|
||||||
}
|
|
||||||
}, [loading, mounted]);
|
|
||||||
|
|
||||||
const handleSearchInputChange = (event) => {
|
|
||||||
const query = event.target.value;
|
|
||||||
makeApiRequest(dataApi + "?search=" + query);
|
|
||||||
setSearchQuery(query);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSort = (columnKey) => {
|
|
||||||
const isAsc = orderBy === columnKey && order === "asc";
|
|
||||||
setOrderBy(columnKey);
|
|
||||||
setOrder(isAsc ? "desc" : "asc");
|
|
||||||
setSortedColumn(columnKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
const sortedData = stableSort(filteredData, getComparator(order, orderBy));
|
|
||||||
const visibleRows = sortedData.slice(
|
|
||||||
page * rowsPerPage,
|
|
||||||
page * rowsPerPage + rowsPerPage
|
|
||||||
);
|
|
||||||
|
|
||||||
function stableSort(array, comparator) {
|
|
||||||
const stabilizedThis = array.map((el, index) => [el, index]);
|
|
||||||
stabilizedThis.sort((a, b) => {
|
|
||||||
const order = comparator(a[0], b[0]);
|
|
||||||
if (order !== 0) return order;
|
|
||||||
return a[1] - b[1];
|
|
||||||
});
|
|
||||||
return stabilizedThis.map((el) => el[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getComparator(order, orderBy) {
|
|
||||||
return order === "desc"
|
|
||||||
? (a, b) => descendingComparator(a, b, orderBy)
|
|
||||||
: (a, b) => -descendingComparator(a, b, orderBy);
|
|
||||||
}
|
|
||||||
|
|
||||||
function descendingComparator(a, b, orderBy) {
|
|
||||||
if (b[orderBy] < a[orderBy]) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (b[orderBy] > a[orderBy]) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleMenuClick = (event, rowIndex) => {
|
|
||||||
setAnchorEls((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[rowIndex]: event.currentTarget,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMenuClose = (rowIndex) => {
|
|
||||||
setAnchorEls((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[rowIndex]: null,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{loading ? (
|
|
||||||
<center>
|
|
||||||
<img
|
|
||||||
src="./assets/img/loader.gif"
|
|
||||||
height="30px"
|
|
||||||
width="30px"
|
|
||||||
alt="Loading"
|
|
||||||
/>
|
|
||||||
</center>
|
|
||||||
) : (
|
|
||||||
<div className="row">
|
|
||||||
<Card
|
|
||||||
className="col-md-12"
|
|
||||||
style={{ marginBottom: "10px", backgroundColor: "#A9A9A9" }}
|
|
||||||
>
|
|
||||||
<CardContent>
|
|
||||||
{createRequired && (
|
|
||||||
<FormWithDrawer
|
|
||||||
globalConfig={props.globalConfig}
|
|
||||||
token={props.token}
|
|
||||||
actionBtnName={actionBtnName}
|
|
||||||
inputFields={createField}
|
|
||||||
api={dataApi}
|
|
||||||
createFormTitle={createFormTitle}
|
|
||||||
refreshData={() => getData()}
|
|
||||||
buttonStyle={{ margin: "10px", backgroundColor: "#17202A" }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{searchRequired && (
|
|
||||||
<div className="search-table">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={searchQuery}
|
|
||||||
onChange={handleSearchInputChange}
|
|
||||||
placeholder="Search..."
|
|
||||||
className="search-input-table"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
<TableContainer component={Paper}>
|
|
||||||
<Table aria-label="simple table">
|
|
||||||
<TableHead>
|
|
||||||
<TableRow style={{ backgroundColor: "#17202A" }}>
|
|
||||||
{showField.map((th, index) => {
|
|
||||||
const isSorted = orderBy === th.key;
|
|
||||||
const isAsc = orderBy === th.key && order === "asc";
|
|
||||||
return (
|
|
||||||
<TableCell
|
|
||||||
key={index}
|
|
||||||
style={{ color: "#FFF" }}
|
|
||||||
onClick={() => handleSort(th.key)}
|
|
||||||
>
|
|
||||||
{th.label} {isSorted && (isAsc ? "▲" : "▼")}
|
|
||||||
</TableCell>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{manageRecord && (
|
|
||||||
<TableCell style={{ textAlign: "center", color: "#FFF" }}>
|
|
||||||
Action
|
|
||||||
</TableCell>
|
|
||||||
)}
|
|
||||||
</TableRow>
|
|
||||||
</TableHead>
|
|
||||||
<TableBody>
|
|
||||||
{visibleRows.map((data, rowIndex) => (
|
|
||||||
<TableRow
|
|
||||||
key={rowIndex}
|
|
||||||
style={
|
|
||||||
data.is_disabled
|
|
||||||
? {
|
|
||||||
backgroundColor: "#e0dfff",
|
|
||||||
borderBottom: "2px dashed orange",
|
|
||||||
}
|
|
||||||
: {}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{showField.map((field, i) => (
|
|
||||||
<TableCell key={i}>{data[field.key]}</TableCell>
|
|
||||||
))}
|
|
||||||
{manageRecord && (
|
|
||||||
<TableCell>
|
|
||||||
{editRequired && (
|
|
||||||
<FormWithDrawer
|
|
||||||
globalConfig={props.globalConfig}
|
|
||||||
token={props.token}
|
|
||||||
actionBtnName="Edit"
|
|
||||||
inputFields={editField}
|
|
||||||
data={data}
|
|
||||||
api={dataApi}
|
|
||||||
onClick={() => handleMenuClose(rowIndex)}
|
|
||||||
refreshData={() => getData()}
|
|
||||||
buttonStyle={{ fontSize: "12px", padding: "5px" }}
|
|
||||||
buttonVarient="outlined"
|
|
||||||
updateFormTitle={updateFormTitle}
|
|
||||||
submitBtnTitle="Update Data"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Button
|
|
||||||
id={`fade-button-${rowIndex}`}
|
|
||||||
aria-controls={
|
|
||||||
anchorEls[rowIndex]
|
|
||||||
? `fade-menu-${rowIndex}`
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded={
|
|
||||||
anchorEls[rowIndex] ? "true" : undefined
|
|
||||||
}
|
|
||||||
onClick={(event) => handleMenuClick(event, rowIndex)}
|
|
||||||
style={{ padding: "5px" }}
|
|
||||||
>
|
|
||||||
<MoreVertIcon />
|
|
||||||
</Button>
|
|
||||||
<Menu
|
|
||||||
id={`fade-menu-${rowIndex}`}
|
|
||||||
MenuListProps={{
|
|
||||||
"aria-labelledby": `fade-button-${rowIndex}`,
|
|
||||||
}}
|
|
||||||
anchorEl={anchorEls[rowIndex]}
|
|
||||||
open={Boolean(anchorEls[rowIndex])}
|
|
||||||
onClose={() => handleMenuClose(rowIndex)}
|
|
||||||
TransitionComponent={Fade}
|
|
||||||
>
|
|
||||||
{data.is_deleted ? (
|
|
||||||
<MenuItem onClick={() => restore(data)}>
|
|
||||||
Show Record
|
|
||||||
</MenuItem>
|
|
||||||
) : (
|
|
||||||
<MenuItem onClick={() => softDelete(data)}>
|
|
||||||
Hide Record
|
|
||||||
</MenuItem>
|
|
||||||
)}
|
|
||||||
<MenuItem onClick={() => forceDelete(data)}>
|
|
||||||
Remove Record
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
</TableCell>
|
|
||||||
)}
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
<Pagination
|
|
||||||
nextPage={nextPage}
|
|
||||||
previousPage={previousPage}
|
|
||||||
makeApiRequest={pageChangeRequest}
|
|
||||||
getValueFromUrl={getValueFromUrl}
|
|
||||||
dataApi={dataApi}
|
|
||||||
totalCount={totalCount}
|
|
||||||
rowsPerPage={rowsPerPage}
|
|
||||||
currentPage={currentPage}
|
|
||||||
setCurrentPage={setCurrentPage}
|
|
||||||
/>
|
|
||||||
</TableContainer>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default APIManager;
|
|
|
@ -1,109 +0,0 @@
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import TextField from "@mui/material/TextField";
|
|
||||||
import Autocomplete from "@mui/material/Autocomplete";
|
|
||||||
import useApi from "../useApi";
|
|
||||||
import { toast } from "react-toastify";
|
|
||||||
|
|
||||||
const AutoCompleteField = (props) => {
|
|
||||||
const [api, setApi] = useState(props.api);
|
|
||||||
const searchOptionHook = props.searchOptionHook;
|
|
||||||
const fieldLabel = props.label;
|
|
||||||
const fieldName = props.name;
|
|
||||||
const optionKey = props.optionKey ? props.optionKey : "id";
|
|
||||||
const [searchData, setSearchData] = useState([]);
|
|
||||||
const [storageData, setStorageData] = useState(
|
|
||||||
JSON.parse(localStorage.getItem("dynamicField"))
|
|
||||||
);
|
|
||||||
const [value, setValue] = useState("");
|
|
||||||
const { Get } = useApi();
|
|
||||||
const [tempValue, setTempValue] = useState(
|
|
||||||
storageData
|
|
||||||
? storageData[storageData.findIndex((item) => item.name === fieldName)]
|
|
||||||
: ""
|
|
||||||
);
|
|
||||||
|
|
||||||
let newApi = async () => {
|
|
||||||
let tempApi = api;
|
|
||||||
if (props.hook != undefined) {
|
|
||||||
tempApi = `${tempApi}${
|
|
||||||
storageData[storageData.findIndex((item) => item.name === props.hook)]
|
|
||||||
.key
|
|
||||||
}/`;
|
|
||||||
}
|
|
||||||
return tempApi;
|
|
||||||
};
|
|
||||||
|
|
||||||
let getdata = async () => {
|
|
||||||
try{
|
|
||||||
const tempApi = await newApi();
|
|
||||||
let response = await Get(tempApi);
|
|
||||||
let _searchData = [];
|
|
||||||
await response.data.map((data) => {
|
|
||||||
_searchData.push({
|
|
||||||
label: data[searchOptionHook],
|
|
||||||
key: data[optionKey],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
setSearchData(_searchData);
|
|
||||||
}catch{
|
|
||||||
toast.error("Something went wrong contact humbingo.")
|
|
||||||
}
|
|
||||||
// await axios
|
|
||||||
// .get(tempApi)
|
|
||||||
// .then(async (response) => {
|
|
||||||
// let _searchData = [];
|
|
||||||
// await response.data.map((data) => {
|
|
||||||
// _searchData.push({
|
|
||||||
// label: data[searchOptionHook],
|
|
||||||
// key: data[optionKey],
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// setSearchData(_searchData);
|
|
||||||
// })
|
|
||||||
// .catch((error) => {
|
|
||||||
// console.error(error);
|
|
||||||
// });
|
|
||||||
};
|
|
||||||
useEffect(() => {
|
|
||||||
getdata();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
let getDataFromJson = (e) => {
|
|
||||||
const acccess = e.target.value;
|
|
||||||
let respData = searchData.find((f) => f.label === acccess);
|
|
||||||
|
|
||||||
respData ? setValue(respData.key) : console.log("this is undefined");
|
|
||||||
if (props.onBlur != undefined) {
|
|
||||||
if (respData != undefined) {
|
|
||||||
props.onBlur(respData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return searchData.length > 0 ? (
|
|
||||||
<>
|
|
||||||
<div style={{ display: "flex" }}>
|
|
||||||
<div style={{ flex: 1 }}>
|
|
||||||
<Autocomplete
|
|
||||||
disablePortal
|
|
||||||
id="combo-box-demo"
|
|
||||||
style={props.style}
|
|
||||||
options={searchData}
|
|
||||||
onBlur={(e) => getDataFromJson(e)}
|
|
||||||
value={tempValue}
|
|
||||||
renderInput={(params) => (
|
|
||||||
<TextField {...params} label={fieldLabel} variant="standard" />
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{/* onSelect={(e) => getDataFromJson(e)} */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input value={value} name={fieldName} hidden readOnly />
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
""
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AutoCompleteField;
|
|
|
@ -1,416 +0,0 @@
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import { toast } from "react-toastify";
|
|
||||||
import "react-toastify/dist/ReactToastify.css";
|
|
||||||
import Swal from "sweetalert2";
|
|
||||||
import "./style.css";
|
|
||||||
import useAPIManager from "./useAPIManager";
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Table,
|
|
||||||
TableBody,
|
|
||||||
TableCell,
|
|
||||||
TableContainer,
|
|
||||||
TableHead,
|
|
||||||
TableRow,
|
|
||||||
Paper,
|
|
||||||
Menu,
|
|
||||||
MenuItem,
|
|
||||||
Fade,
|
|
||||||
Card,
|
|
||||||
CardContent,
|
|
||||||
} from "@mui/material";
|
|
||||||
import FormWithDrawer from "./FormWithDrawer";
|
|
||||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
|
||||||
import Pagination from "./Pagination";
|
|
||||||
|
|
||||||
function CrudManager(props) {
|
|
||||||
const dataSchema = props.data;
|
|
||||||
const { Get, Delete, Patch, getAPI, getHost } = useAPIManager(
|
|
||||||
props.globalConfig,
|
|
||||||
props.token
|
|
||||||
);
|
|
||||||
const dataApi = getAPI(props.data.api);
|
|
||||||
const [apiData, setApiData] = useState([]);
|
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
|
||||||
const [orderBy, setOrderBy] = useState(""); // Column to sort
|
|
||||||
const [order, setOrder] = useState("asc");
|
|
||||||
const [page, setPage] = useState(0);
|
|
||||||
const [rowsPerPage, setRowsPerPage] = useState(50);
|
|
||||||
const [sortedColumn, setSortedColumn] = useState(null);
|
|
||||||
const [filteredData, setFilteredData] = useState([]);
|
|
||||||
const [anchorEls, setAnchorEls] = useState({}); // Updated state for menu anchors
|
|
||||||
const [mounted, setMounted] = useState(false);
|
|
||||||
const [nextPage, setNextPage] = useState(null);
|
|
||||||
const [previousPage, setPreviousPage] = useState(null);
|
|
||||||
const [totalCount, setTotalCount] = useState(0);
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
|
|
||||||
const updateFormTitle = props.updateFormTitle ? props.updateFormTitle : "";
|
|
||||||
const createFormTitle = props.createFormTitle ? props.createFormTitle : "";
|
|
||||||
const actionBtnName = props.actionBtnName
|
|
||||||
? props.actionBtnName
|
|
||||||
: "Create New Data";
|
|
||||||
const createRequired = props.createRequired === false ? false : true;
|
|
||||||
const editRequired = props.editRequired === false ? false : true;
|
|
||||||
const searchRequired = props.searchRequired === false ? false : true;
|
|
||||||
|
|
||||||
const createField = dataSchema.createField;
|
|
||||||
const editField = dataSchema.editField;
|
|
||||||
const showField = dataSchema.showField;
|
|
||||||
const manageRecord = true;
|
|
||||||
|
|
||||||
let navigate = useNavigate();
|
|
||||||
const getData = async () => {
|
|
||||||
makeApiRequest(dataApi);
|
|
||||||
};
|
|
||||||
|
|
||||||
const makeApiRequest = async (api) => {
|
|
||||||
try {
|
|
||||||
setSearchQuery("");
|
|
||||||
const result = await Get(api ? api : dataApi);
|
|
||||||
setNextPage(result.next);
|
|
||||||
setPreviousPage(result.previous);
|
|
||||||
setTotalCount(result.count);
|
|
||||||
setApiData(result.results);
|
|
||||||
setFilteredData(result.results);
|
|
||||||
} catch (err) {
|
|
||||||
if (err.code == "ERR_BAD_REQUEST") {
|
|
||||||
toast.error("Unauthorised access to page, Contact admin for access.");
|
|
||||||
navigate("/");
|
|
||||||
} else {
|
|
||||||
toast.error(err.message);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const pageChangeRequest = (url) => {
|
|
||||||
if (getPageUrl(url) != null) {
|
|
||||||
makeApiRequest(getHost() + getPageUrl(url));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
async function softDelete(data) {
|
|
||||||
try {
|
|
||||||
await Patch(dataApi, data["id"], { is_deleted: true })
|
|
||||||
.then(() => {
|
|
||||||
toast.success("Record updated successfully!");
|
|
||||||
getData();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
getData();
|
|
||||||
toast.error(err || "Error");
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
getData();
|
|
||||||
toast.error("Something Went wrong contact Humbingo");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function restore(data) {
|
|
||||||
try {
|
|
||||||
await Patch(dataApi, data["id"], { is_deleted: false })
|
|
||||||
.then(() => {
|
|
||||||
toast.success("Record updated successfully!");
|
|
||||||
getData();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
getData();
|
|
||||||
toast.error(err || "Error");
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
getData();
|
|
||||||
toast.error("Something Went wrong contact Humbingo");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function forceDelete(data) {
|
|
||||||
await Swal.fire({
|
|
||||||
title: "Data will be removed permanently! Are you sure?",
|
|
||||||
icon: "warning",
|
|
||||||
showCancelButton: true,
|
|
||||||
confirmButtonColor: "#3085d6",
|
|
||||||
cancelButtonColor: "#d33",
|
|
||||||
confirmButtonText: "Yes, delete it!",
|
|
||||||
}).then(async (result) => {
|
|
||||||
if (result.isConfirmed) {
|
|
||||||
try {
|
|
||||||
await Delete(dataApi, data["id"])
|
|
||||||
.then(() => {
|
|
||||||
toast.success("Record updated successfully!");
|
|
||||||
getData();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
getData();
|
|
||||||
toast.error(err || "Error");
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
getData();
|
|
||||||
toast.error("Something Went wrong contact Humbingo");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const getValueFromUrl = (url, parameterName) => {
|
|
||||||
try {
|
|
||||||
const regex = new RegExp(`${parameterName}=([^&]+)`);
|
|
||||||
const match = url.match(regex);
|
|
||||||
return match ? match[1] : null;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function getPageUrl(url) {
|
|
||||||
let urls = "";
|
|
||||||
try {
|
|
||||||
const urlObject = new URL(url);
|
|
||||||
urls = urlObject.pathname + urlObject.search;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return urls;
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMounted(true);
|
|
||||||
return () => {
|
|
||||||
setMounted(false);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (loading && mounted) {
|
|
||||||
getData();
|
|
||||||
}
|
|
||||||
}, [loading, mounted]);
|
|
||||||
|
|
||||||
const handleSearchInputChange = (event) => {
|
|
||||||
const query = event.target.value;
|
|
||||||
makeApiRequest(dataApi + "?search=" + query);
|
|
||||||
setSearchQuery(query);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSort = (columnKey) => {
|
|
||||||
const isAsc = orderBy === columnKey && order === "asc";
|
|
||||||
setOrderBy(columnKey);
|
|
||||||
setOrder(isAsc ? "desc" : "asc");
|
|
||||||
setSortedColumn(columnKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
const sortedData = stableSort(filteredData, getComparator(order, orderBy));
|
|
||||||
const visibleRows = sortedData.slice(
|
|
||||||
page * rowsPerPage,
|
|
||||||
page * rowsPerPage + rowsPerPage
|
|
||||||
);
|
|
||||||
|
|
||||||
function stableSort(array, comparator) {
|
|
||||||
const stabilizedThis = array.map((el, index) => [el, index]);
|
|
||||||
stabilizedThis.sort((a, b) => {
|
|
||||||
const order = comparator(a[0], b[0]);
|
|
||||||
if (order !== 0) return order;
|
|
||||||
return a[1] - b[1];
|
|
||||||
});
|
|
||||||
return stabilizedThis.map((el) => el[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getComparator(order, orderBy) {
|
|
||||||
return order === "desc"
|
|
||||||
? (a, b) => descendingComparator(a, b, orderBy)
|
|
||||||
: (a, b) => -descendingComparator(a, b, orderBy);
|
|
||||||
}
|
|
||||||
|
|
||||||
function descendingComparator(a, b, orderBy) {
|
|
||||||
if (b[orderBy] < a[orderBy]) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (b[orderBy] > a[orderBy]) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleMenuClick = (event, rowIndex) => {
|
|
||||||
setAnchorEls((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[rowIndex]: event.currentTarget,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMenuClose = (rowIndex) => {
|
|
||||||
setAnchorEls((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[rowIndex]: null,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{loading ? (
|
|
||||||
<center>
|
|
||||||
<img
|
|
||||||
src="./assets/img/loader.gif"
|
|
||||||
height="30px"
|
|
||||||
width="30px"
|
|
||||||
alt="Loading"
|
|
||||||
/>
|
|
||||||
</center>
|
|
||||||
) : (
|
|
||||||
<div className="row">
|
|
||||||
<Card
|
|
||||||
className="col-md-12"
|
|
||||||
style={{ marginBottom: "10px", backgroundColor: "#A9A9A9" }}
|
|
||||||
>
|
|
||||||
<CardContent>
|
|
||||||
{createRequired && (
|
|
||||||
<FormWithDrawer
|
|
||||||
globalConfig={props.globalConfig}
|
|
||||||
token={props.token}
|
|
||||||
actionBtnName={actionBtnName}
|
|
||||||
inputFields={createField}
|
|
||||||
api={dataApi}
|
|
||||||
createFormTitle={createFormTitle}
|
|
||||||
refreshData={() => getData()}
|
|
||||||
buttonStyle={{ margin: "10px", backgroundColor: "#17202A" }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{searchRequired && (
|
|
||||||
<div className="search-table">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={searchQuery}
|
|
||||||
onChange={handleSearchInputChange}
|
|
||||||
placeholder="Search..."
|
|
||||||
className="search-input-table"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
<TableContainer component={Paper}>
|
|
||||||
<Table aria-label="simple table">
|
|
||||||
<TableHead>
|
|
||||||
<TableRow style={{ backgroundColor: "#17202A" }}>
|
|
||||||
{showField.map((th, index) => {
|
|
||||||
const isSorted = orderBy === th.key;
|
|
||||||
const isAsc = orderBy === th.key && order === "asc";
|
|
||||||
return (
|
|
||||||
<TableCell
|
|
||||||
key={index}
|
|
||||||
style={{ color: "#FFF" }}
|
|
||||||
onClick={() => handleSort(th.key)}
|
|
||||||
>
|
|
||||||
{th.label} {isSorted && (isAsc ? "▲" : "▼")}
|
|
||||||
</TableCell>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{manageRecord && (
|
|
||||||
<TableCell style={{ textAlign: "center", color: "#FFF" }}>
|
|
||||||
Action
|
|
||||||
</TableCell>
|
|
||||||
)}
|
|
||||||
</TableRow>
|
|
||||||
</TableHead>
|
|
||||||
<TableBody>
|
|
||||||
{visibleRows.map((data, rowIndex) => (
|
|
||||||
<TableRow
|
|
||||||
key={rowIndex}
|
|
||||||
style={
|
|
||||||
data.is_disabled
|
|
||||||
? {
|
|
||||||
backgroundColor: "#e0dfff",
|
|
||||||
borderBottom: "2px dashed orange",
|
|
||||||
}
|
|
||||||
: {}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{showField.map((field, i) => (
|
|
||||||
<TableCell key={i}>{data[field.key]}</TableCell>
|
|
||||||
))}
|
|
||||||
{manageRecord && (
|
|
||||||
<TableCell>
|
|
||||||
{editRequired && (
|
|
||||||
<FormWithDrawer
|
|
||||||
globalConfig={props.globalConfig}
|
|
||||||
token={props.token}
|
|
||||||
actionBtnName="Edit"
|
|
||||||
inputFields={editField}
|
|
||||||
data={data}
|
|
||||||
api={dataApi}
|
|
||||||
onClick={() => handleMenuClose(rowIndex)}
|
|
||||||
refreshData={() => getData()}
|
|
||||||
buttonStyle={{ fontSize: "12px", padding: "5px" }}
|
|
||||||
buttonVarient="outlined"
|
|
||||||
updateFormTitle={updateFormTitle}
|
|
||||||
submitBtnTitle="Update Data"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Button
|
|
||||||
id={`fade-button-${rowIndex}`}
|
|
||||||
aria-controls={
|
|
||||||
anchorEls[rowIndex]
|
|
||||||
? `fade-menu-${rowIndex}`
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded={
|
|
||||||
anchorEls[rowIndex] ? "true" : undefined
|
|
||||||
}
|
|
||||||
onClick={(event) => handleMenuClick(event, rowIndex)}
|
|
||||||
style={{ padding: "5px" }}
|
|
||||||
>
|
|
||||||
<MoreVertIcon />
|
|
||||||
</Button>
|
|
||||||
<Menu
|
|
||||||
id={`fade-menu-${rowIndex}`}
|
|
||||||
MenuListProps={{
|
|
||||||
"aria-labelledby": `fade-button-${rowIndex}`,
|
|
||||||
}}
|
|
||||||
anchorEl={anchorEls[rowIndex]}
|
|
||||||
open={Boolean(anchorEls[rowIndex])}
|
|
||||||
onClose={() => handleMenuClose(rowIndex)}
|
|
||||||
TransitionComponent={Fade}
|
|
||||||
>
|
|
||||||
{data.is_deleted ? (
|
|
||||||
<MenuItem onClick={() => restore(data)}>
|
|
||||||
Show Record
|
|
||||||
</MenuItem>
|
|
||||||
) : (
|
|
||||||
<MenuItem onClick={() => softDelete(data)}>
|
|
||||||
Hide Record
|
|
||||||
</MenuItem>
|
|
||||||
)}
|
|
||||||
<MenuItem onClick={() => forceDelete(data)}>
|
|
||||||
Remove Record
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
</TableCell>
|
|
||||||
)}
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
<Pagination
|
|
||||||
nextPage={nextPage}
|
|
||||||
previousPage={previousPage}
|
|
||||||
makeApiRequest={pageChangeRequest}
|
|
||||||
getValueFromUrl={getValueFromUrl}
|
|
||||||
dataApi={dataApi}
|
|
||||||
totalCount={totalCount}
|
|
||||||
rowsPerPage={rowsPerPage}
|
|
||||||
currentPage={currentPage}
|
|
||||||
setCurrentPage={setCurrentPage}
|
|
||||||
/>
|
|
||||||
</TableContainer>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CrudManager;
|
|
|
@ -1,87 +0,0 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import TextField from "@mui/material/TextField";
|
|
||||||
import Autocomplete from "@mui/material/Autocomplete";
|
|
||||||
import CircularProgress from '@mui/material/CircularProgress';
|
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
|
|
||||||
const CustomAutocomplete = ({ apiUrl, displayKey, valueKey, onValueChange, inputName, variant , label, sameAsSeen}) => {
|
|
||||||
|
|
||||||
const [options, setOptions] = useState([]);
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [inputValue, setInputValue] = useState('');
|
|
||||||
const [selectedOption, setSelectedOption] = useState(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setLoading(true);
|
|
||||||
axios.get(apiUrl)
|
|
||||||
.then(response => {
|
|
||||||
setOptions(response.data);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error fetching data:', error);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
}, [apiUrl]);
|
|
||||||
|
|
||||||
const handleInputChange = (event, newValue) => {
|
|
||||||
setInputValue(newValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOptionSelect = (event, newValue) => {
|
|
||||||
// console.log("Selected value:");
|
|
||||||
// console.log(newValue);
|
|
||||||
setSelectedOption(newValue);
|
|
||||||
setInputValue(newValue ? newValue[displayKey] : '');
|
|
||||||
onValueChange(newValue, inputName); // Pass the name attribute value along with the value
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Autocomplete
|
|
||||||
|
|
||||||
inputValue={inputValue}
|
|
||||||
onInputChange={handleInputChange}
|
|
||||||
options={options}
|
|
||||||
loading={loading}
|
|
||||||
onChange={handleOptionSelect}
|
|
||||||
getOptionLabel={(option) => option ? option[displayKey] : ''}
|
|
||||||
renderInput={(params) => (
|
|
||||||
<TextField
|
|
||||||
{...params}
|
|
||||||
label={label}
|
|
||||||
variant={variant}
|
|
||||||
InputProps={{
|
|
||||||
...params.InputProps,
|
|
||||||
endAdornment: (
|
|
||||||
<>
|
|
||||||
{loading ? <CircularProgress color="secondary" size={20} /> : null}
|
|
||||||
{params.InputProps.endAdornment}
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
)}
|
|
||||||
|
|
||||||
/>
|
|
||||||
<input hidden name={inputName} value={selectedOption ? selectedOption[valueKey] : ''} style={{display: 'none'}}/>
|
|
||||||
{(sameAsSeen)?<input hidden name={"_"+inputName} value={selectedOption ? selectedOption[displayKey] : ''} style={{display: 'none'}}/>:""}
|
|
||||||
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
CustomAutocomplete.propTypes = {
|
|
||||||
apiUrl: PropTypes.string.isRequired,
|
|
||||||
displayKey: PropTypes.string.isRequired,
|
|
||||||
valueKey: PropTypes.string.isRequired,
|
|
||||||
onValueChange: PropTypes.func.isRequired,
|
|
||||||
inputName: PropTypes.string.isRequired, // Accept inputName prop
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CustomAutocomplete;
|
|
|
@ -1,112 +0,0 @@
|
||||||
import React, { useState } from 'react';
|
|
||||||
import CustomAutocomplete from './Autocomplete';
|
|
||||||
import _Autocomplete from './_Autocomplete';
|
|
||||||
const DynamicAutocomplete = (props) => {
|
|
||||||
// [
|
|
||||||
// {
|
|
||||||
// "apiUrl": 'https://api.udaymotors.in/api/v1/user/',
|
|
||||||
// "displayKey": 'phone_no',
|
|
||||||
// "valueKey": 'id',
|
|
||||||
// "name": "user",
|
|
||||||
// "label":"User"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "apiUrl": 'https://api.udaymotors.in/api/v1/getInvestmentsByUserId/',
|
|
||||||
// "displayKey": 'investment_id',
|
|
||||||
// "valueKey": 'id',
|
|
||||||
// "name": "investment",
|
|
||||||
// "parent": "user",
|
|
||||||
// "parent_value_key": "id",
|
|
||||||
// "label":"Investments"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "apiUrl": 'https://api.udaymotors.in/api/v1/transaction/',
|
|
||||||
// "displayKey": 'description',
|
|
||||||
// "name": "transaction",
|
|
||||||
// "valueKey": 'id',
|
|
||||||
// "parent": "investment",
|
|
||||||
// "parent_value_key": "user_id",
|
|
||||||
// "label":"Transactions"
|
|
||||||
// },
|
|
||||||
// ]
|
|
||||||
const [selectedValues, setSelectedValues] = useState([]);
|
|
||||||
const [currentFieldIndex, setCurrentFieldIndex] = useState(0);
|
|
||||||
const [fields, setFields] = useState(props.fields);
|
|
||||||
|
|
||||||
const handleValueChange = (value, name) => {
|
|
||||||
const updatedValues = [...selectedValues];
|
|
||||||
const existingIndex = updatedValues.findIndex(item => item.name === name);
|
|
||||||
if (existingIndex !== -1) {
|
|
||||||
updatedValues[existingIndex] = { value, name };
|
|
||||||
} else {
|
|
||||||
updatedValues.push({ value, name });
|
|
||||||
}
|
|
||||||
|
|
||||||
setSelectedValues(updatedValues);
|
|
||||||
|
|
||||||
// Update the API URL of the next field
|
|
||||||
const nextFieldIndex = currentFieldIndex + 1;
|
|
||||||
if (nextFieldIndex < fields.length) {
|
|
||||||
const nextField = fields[nextFieldIndex];
|
|
||||||
const parentValue = updatedValues.find(item => item.name === nextField.parent)?.value[nextField.parent_value_key];
|
|
||||||
if (parentValue) {
|
|
||||||
const updatedFields = [...fields];
|
|
||||||
updatedFields[nextFieldIndex] = {
|
|
||||||
...nextField,
|
|
||||||
apiUrl: `${nextField.apiUrl}${parentValue}/`
|
|
||||||
};
|
|
||||||
setFields(updatedFields);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setCurrentFieldIndex(nextFieldIndex);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleParentValueChange = (parentName, parentValue) => {
|
|
||||||
// Find the index of the parent field
|
|
||||||
const parentFieldIndex = fields.findIndex(field => field.name === parentName);
|
|
||||||
|
|
||||||
// Reset the selected values and fields configurations for the subsequent fields
|
|
||||||
setSelectedValues(selectedValues.slice(0, parentFieldIndex + 1));
|
|
||||||
setFields(fields.slice(0, parentFieldIndex + 1));
|
|
||||||
setCurrentFieldIndex(parentFieldIndex);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
fields.slice(0, currentFieldIndex + 1).map((field, index) => (
|
|
||||||
<div key={index} style={{marginTop: "10px", marginBottom: "10px"}}>
|
|
||||||
{
|
|
||||||
(field.advance)?
|
|
||||||
<_Autocomplete
|
|
||||||
apiUrl={field.apiUrl}
|
|
||||||
displayKey={field.displayKey}
|
|
||||||
valueKey={field.valueKey}
|
|
||||||
inputName={field.name}
|
|
||||||
onValueChange={handleValueChange}
|
|
||||||
onParentValueChange={handleParentValueChange}
|
|
||||||
variant={field.variant}
|
|
||||||
label={field.label}
|
|
||||||
sameAsSeen={field.sameAsSeen}
|
|
||||||
|
|
||||||
defaultObj={(field.defaultObj)?field.defaultObj:""}
|
|
||||||
/>
|
|
||||||
|
|
||||||
:<CustomAutocomplete
|
|
||||||
apiUrl={field.apiUrl}
|
|
||||||
displayKey={field.displayKey}
|
|
||||||
valueKey={field.valueKey}
|
|
||||||
inputName={field.name}
|
|
||||||
onValueChange={handleValueChange}
|
|
||||||
onParentValueChange={handleParentValueChange}
|
|
||||||
variant={field.variant}
|
|
||||||
label={field.label}
|
|
||||||
sameAsSeen={field.sameAsSeen}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DynamicAutocomplete;
|
|
|
@ -1,109 +0,0 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import TextField from "@mui/material/TextField";
|
|
||||||
import Autocomplete from "@mui/material/Autocomplete";
|
|
||||||
import CircularProgress from '@mui/material/CircularProgress';
|
|
||||||
import useAPIManager from '../useAPIManager';
|
|
||||||
|
|
||||||
|
|
||||||
const _Autocomplete = (props) => {
|
|
||||||
const {
|
|
||||||
apiUrl,
|
|
||||||
displayKey,
|
|
||||||
valueKey,
|
|
||||||
onValueChange,
|
|
||||||
inputName,
|
|
||||||
variant,
|
|
||||||
label,
|
|
||||||
sameAsSeen,
|
|
||||||
defaultObj,
|
|
||||||
onBlur,
|
|
||||||
onFocus,
|
|
||||||
options: propOptions
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
|
|
||||||
const [options, setOptions] = useState(propOptions || []);
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [inputValue, setInputValue] = useState('');
|
|
||||||
const [selectedOption, setSelectedOption] = useState(defaultObj);
|
|
||||||
const {Get, Post} =useAPIManager(props.globalConfig, props.token);
|
|
||||||
useEffect(() => {
|
|
||||||
setLoading(true);
|
|
||||||
getSearchData(apiUrl)
|
|
||||||
}, [apiUrl]);
|
|
||||||
|
|
||||||
const handleInputChange = (event, newValue) => {
|
|
||||||
getSearchData(apiUrl+"?search="+newValue)
|
|
||||||
setInputValue(newValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSearchData = async (api) =>{
|
|
||||||
await Get(api)
|
|
||||||
.then(response => {
|
|
||||||
(response.results)?setOptions(response.results):setOptions(response)
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error fetching data:', error);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleOptionSelect = (event, newValue) => {
|
|
||||||
setSelectedOption(newValue);
|
|
||||||
setInputValue(newValue ? newValue[displayKey] : '');
|
|
||||||
onValueChange(newValue, inputName); // Pass the name attribute value along with the value
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Autocomplete
|
|
||||||
inputValue={inputValue}
|
|
||||||
onInputChange={handleInputChange}
|
|
||||||
options={options}
|
|
||||||
loading={loading}
|
|
||||||
onChange={handleOptionSelect}
|
|
||||||
getOptionLabel={(option) => option ? option[displayKey] : ''}
|
|
||||||
defaultValue= { defaultObj}
|
|
||||||
renderInput={(params) => (
|
|
||||||
<TextField
|
|
||||||
{...params}
|
|
||||||
label={label}
|
|
||||||
variant={variant}
|
|
||||||
onBlur={onBlur}
|
|
||||||
onFocus={onFocus}
|
|
||||||
InputProps={{
|
|
||||||
...params.InputProps,
|
|
||||||
endAdornment: (
|
|
||||||
<>
|
|
||||||
{loading ? <CircularProgress color="secondary" size={20} /> : null}
|
|
||||||
{params.InputProps.endAdornment}
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
)}
|
|
||||||
|
|
||||||
/>
|
|
||||||
{/* {console.log(selectedOption)} */}
|
|
||||||
<input hidden name={inputName} value={selectedOption ? selectedOption[valueKey] : ''} style={{display: 'none'}}/>
|
|
||||||
{(sameAsSeen)?<input hidden name={"_"+inputName} value={selectedOption ? selectedOption[displayKey] : ''} style={{display: 'none'}}/>:""}
|
|
||||||
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
_Autocomplete.propTypes = {
|
|
||||||
apiUrl: PropTypes.string.isRequired,
|
|
||||||
displayKey: PropTypes.string.isRequired,
|
|
||||||
valueKey: PropTypes.string.isRequired,
|
|
||||||
onValueChange: PropTypes.func.isRequired,
|
|
||||||
inputName: PropTypes.string.isRequired, // Accept inputName prop
|
|
||||||
};
|
|
||||||
|
|
||||||
export default _Autocomplete;
|
|
|
@ -1,84 +0,0 @@
|
||||||
import React, { useState } from "react";
|
|
||||||
import Drawer from "@mui/material/Drawer";
|
|
||||||
import { Button, TextField } from "@mui/material";
|
|
||||||
import { firstUpperCase } from "./helper.js";
|
|
||||||
function EditRow(props) {
|
|
||||||
const editBlock = props.editBlock ? props.editBlock : [];
|
|
||||||
const [state, setState] = React.useState({
|
|
||||||
top: false,
|
|
||||||
left: false,
|
|
||||||
bottom: false,
|
|
||||||
right: false,
|
|
||||||
});
|
|
||||||
const toggleDrawer = (anchor, open) => (event) => {
|
|
||||||
if (
|
|
||||||
event.type === "keydown" &&
|
|
||||||
(event.key === "Tab" || event.key === "Shift")
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setState({ ...state, [anchor]: open });
|
|
||||||
};
|
|
||||||
const [formFields, setFormFields] = useState(props.data);
|
|
||||||
var fields = Object.keys(formFields);
|
|
||||||
const handleSubmit = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
};
|
|
||||||
function doChange(fieldName, value) {
|
|
||||||
setFormFields((prevData) => ({
|
|
||||||
...prevData,
|
|
||||||
[fieldName]: value,
|
|
||||||
}));
|
|
||||||
localStorage.setItem(props.data.id + "_" + fieldName, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{/* {formFields} */}
|
|
||||||
{["right"].map((anchor) => (
|
|
||||||
<React.Fragment key={anchor}>
|
|
||||||
<Button onClick={toggleDrawer(anchor, true)}>Edit</Button>
|
|
||||||
<Drawer
|
|
||||||
anchor={anchor}
|
|
||||||
open={state[anchor]}
|
|
||||||
onClose={toggleDrawer(anchor, false)}
|
|
||||||
>
|
|
||||||
<div className="row" style={{ padding: "10px", width: "500px" }}>
|
|
||||||
<div className="col-md-12">
|
|
||||||
<h4>Edit Details</h4>
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
{fields.map((field, index) => {
|
|
||||||
return (
|
|
||||||
<div key={index} className="dynamic-form-element">
|
|
||||||
{!Object.values(editBlock).includes(field) ? (
|
|
||||||
<>
|
|
||||||
{" "}
|
|
||||||
<TextField
|
|
||||||
variant="standard"
|
|
||||||
name={field}
|
|
||||||
value=""
|
|
||||||
onChange={(e) => doChange(field, e.target.value)}
|
|
||||||
label={firstUpperCase(field)}
|
|
||||||
/>
|
|
||||||
<br />{" "}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
""
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
|
|
||||||
<Button variant="outlined" type="submit">
|
|
||||||
Update
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Drawer>
|
|
||||||
</React.Fragment>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export default EditRow;
|
|
|
@ -1,17 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import CrudManager from './CrudManager'
|
|
||||||
import schema from './example.json'
|
|
||||||
|
|
||||||
const CrudManagerExample = () => {
|
|
||||||
|
|
||||||
return (
|
|
||||||
|
|
||||||
<>
|
|
||||||
<CrudManager data={schema} />
|
|
||||||
{/* // <CRUDManager schema={schema}/> */}
|
|
||||||
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CrudManagerExample
|
|
|
@ -1,148 +0,0 @@
|
||||||
import React,{useState} from "react";
|
|
||||||
import { Button } from "@mui/material";
|
|
||||||
import FormField, { validateField } from "./FormField";
|
|
||||||
import "./style.css";
|
|
||||||
import { toast } from "react-toastify";
|
|
||||||
import useAPIManager from "./useAPIManager";
|
|
||||||
|
|
||||||
const Form = (props) => {
|
|
||||||
const inputFields = props.inputFields;
|
|
||||||
const fieldDefault = props.data ? props.data : [];
|
|
||||||
const submitBtnTitle = props.submitBtnTitle ? props.submitBtnTitle : "Submit";
|
|
||||||
const [externalErrors, setExternalErrors] = useState({});
|
|
||||||
|
|
||||||
const { Get, Delete, Patch, Post, getHost } = useAPIManager(
|
|
||||||
props.globalConfig,
|
|
||||||
props.token
|
|
||||||
);
|
|
||||||
|
|
||||||
async function handleSubmit(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
let isFormValid = true;
|
|
||||||
const newExternalErrors = {};
|
|
||||||
inputFields.forEach((field) => {
|
|
||||||
const fieldName = field.name;
|
|
||||||
const value = e.target.elements[fieldName].value;
|
|
||||||
const validationError = validateField(value, field.type, field.label);
|
|
||||||
|
|
||||||
|
|
||||||
if (field.required) { // Check if the field is required
|
|
||||||
const validationError = validateField(value, field.type, field.label);
|
|
||||||
if (validationError) {
|
|
||||||
newExternalErrors[fieldName] = validationError;
|
|
||||||
toast.error(validationError);
|
|
||||||
isFormValid = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setExternalErrors(newExternalErrors);
|
|
||||||
|
|
||||||
if (!isFormValid) {
|
|
||||||
return; // Don't submit if form is invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = new FormData(e.target);
|
|
||||||
let formData = Object.fromEntries(data.entries());
|
|
||||||
// console.log(formData);
|
|
||||||
|
|
||||||
if (fieldDefault["id"]) {
|
|
||||||
|
|
||||||
try{
|
|
||||||
await Patch(props.api,fieldDefault["id"], formData).then(()=>{
|
|
||||||
props.closeDrawer();
|
|
||||||
props.refreshData();
|
|
||||||
toast.success("Record updated successfully!");
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
// console.error(err);
|
|
||||||
toast.error(err || "Error");
|
|
||||||
});
|
|
||||||
}catch{
|
|
||||||
toast.error("Something Went wrong contact Humbingo");
|
|
||||||
}
|
|
||||||
|
|
||||||
// axios
|
|
||||||
// .patch(props.api + `${fieldDefault["id"]}` + "/", formData)
|
|
||||||
// .then((response) => {
|
|
||||||
// props.closeDrawer();
|
|
||||||
// props.refreshData();
|
|
||||||
// toast.success("Record updated successfully!");
|
|
||||||
// })
|
|
||||||
// .catch((err) => {
|
|
||||||
// // console.error(err);
|
|
||||||
// toast.error(err.response?.data?.error || "An error occurred");
|
|
||||||
// });
|
|
||||||
} else {
|
|
||||||
|
|
||||||
|
|
||||||
try{
|
|
||||||
await Post(props.api, formData).then(()=>{
|
|
||||||
props.closeDrawer();
|
|
||||||
props.refreshData();
|
|
||||||
|
|
||||||
toast.success("Record created successfully!");
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
// console.error(err);
|
|
||||||
toast.error(err.response?.data?.error || "Error");
|
|
||||||
});
|
|
||||||
}catch{
|
|
||||||
toast.error("Something Went wrong contact Humbingo");
|
|
||||||
}
|
|
||||||
// axios
|
|
||||||
// .post(props.api, formData)
|
|
||||||
// .then((response) => {
|
|
||||||
// props.closeDrawer();
|
|
||||||
// props.refreshData();
|
|
||||||
|
|
||||||
// toast.success("Record created successfully!");
|
|
||||||
// })
|
|
||||||
// .catch((err) => {
|
|
||||||
// // console.error(err);
|
|
||||||
// toast.error(err.response?.data?.error || "An error occurred");
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<form onSubmit={handleSubmit} style={{ padding: "20px" }}>
|
|
||||||
{inputFields.map((field, index) => {
|
|
||||||
const fieldName = field["name"];
|
|
||||||
if (props.grid) {
|
|
||||||
return (
|
|
||||||
<div className={props.grid}>
|
|
||||||
<div className="dynamic-form-element" key={index}>
|
|
||||||
<FormField
|
|
||||||
globalConfig={props.globalConfig}
|
|
||||||
token={props.token}
|
|
||||||
field={field}
|
|
||||||
name={index}
|
|
||||||
defaultValue={fieldDefault[fieldName]}
|
|
||||||
handleChange={props.handleChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<div className="dynamic-form-element" key={index}>
|
|
||||||
<FormField
|
|
||||||
globalConfig={props.globalConfig}
|
|
||||||
token={props.token}
|
|
||||||
field={field}
|
|
||||||
name={index}
|
|
||||||
defaultValue={fieldDefault[fieldName]}
|
|
||||||
handleChange={props.handleChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
<br />
|
|
||||||
<Button variant="contained" type="submit" size="small">
|
|
||||||
{submitBtnTitle}
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export default Form;
|
|
|
@ -1,314 +0,0 @@
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { TextField, FormHelperText } from "@mui/material";
|
|
||||||
import { firstUpperCase ,validateEmail,validatePassword} from "./helper.js";
|
|
||||||
import "./style.css";
|
|
||||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
|
||||||
import Checkbox from "@mui/material/Checkbox";
|
|
||||||
import CustomAutocomplete from "./DynamicForm/Autocomplete.js";
|
|
||||||
import _Autocomplete from "./DynamicForm/_Autocomplete.js";
|
|
||||||
|
|
||||||
import useAPIManager from './useAPIManager.js';
|
|
||||||
export const validateField = (value, type, label) => {
|
|
||||||
let errorMessage = "";
|
|
||||||
if (label) {
|
|
||||||
switch (type) {
|
|
||||||
case "text":
|
|
||||||
if (!value) {
|
|
||||||
errorMessage = ` ${label} is required`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "select":
|
|
||||||
if (!value) {
|
|
||||||
errorMessage = ` ${label} Please Select Value`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "simple-select":
|
|
||||||
if (!value) {
|
|
||||||
errorMessage = ` ${label} Please Select`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "advance-select":
|
|
||||||
if (!value) {
|
|
||||||
errorMessage = ` ${label} Please Select`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "datetime-local":
|
|
||||||
if (!value) {
|
|
||||||
errorMessage = `${label} Please Select `;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "checkbox":
|
|
||||||
if (!value) {
|
|
||||||
errorMessage = `${label} Must be Checked`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "email":
|
|
||||||
if (!value || !validateEmail(value)) {
|
|
||||||
errorMessage = `${label} must be a valid email address`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "password":
|
|
||||||
if (!value || !validatePassword(value)) {
|
|
||||||
errorMessage = `${label} must be at least 8 characters long`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "phone":
|
|
||||||
if (!value || value.length !== 10) {
|
|
||||||
errorMessage = `${label} must be exactly 10 characters`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!value || !value.trim()) {
|
|
||||||
errorMessage = `${label} Is Required`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errorMessage;
|
|
||||||
};
|
|
||||||
|
|
||||||
const FormField = (props) => {
|
|
||||||
const { Get, Delete, Patch, Post, getAPI } = useAPIManager(
|
|
||||||
props.globalConfig,
|
|
||||||
props.token
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
const required = props.field.required;
|
|
||||||
const label = firstUpperCase(props.field.label);
|
|
||||||
let fieldLabel = required ? (
|
|
||||||
<span>
|
|
||||||
<b style={{ color: "red" }}>*</b> {label}
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
label
|
|
||||||
);
|
|
||||||
const type = props.field.type;
|
|
||||||
const varient = props.field.varient;
|
|
||||||
const placeholder = props.field.placeholder;
|
|
||||||
const isDynamic = props.field.dynamic;
|
|
||||||
const hook = props.field.hook;
|
|
||||||
const defaultObj = props.field.defaultObj;
|
|
||||||
const dafaultValue = props.field.defaultValue
|
|
||||||
? props.field.defaultValue
|
|
||||||
: props.defaultValue;
|
|
||||||
const name = props.field.name;
|
|
||||||
|
|
||||||
let optionKey = "";
|
|
||||||
let searchApi = "";
|
|
||||||
let searchOptionHook = "";
|
|
||||||
|
|
||||||
if (props.field.search) {
|
|
||||||
searchApi = props.field.search.api ? props.field.search.api : "";
|
|
||||||
// console.log("My Search APu 1", searchApi);
|
|
||||||
searchApi = searchApi.length > 0 ? getAPI(searchApi) : "";
|
|
||||||
|
|
||||||
searchOptionHook = props.field.search.label ? props.field.search.label : "";
|
|
||||||
optionKey = props.field.search.key ? props.field.search.key : "id";
|
|
||||||
}
|
|
||||||
const [value, setValue] = useState(dafaultValue);
|
|
||||||
const [isChecked, setIsChecked] = useState(dafaultValue);
|
|
||||||
const [storageData, setStorageData] = useState([]);
|
|
||||||
|
|
||||||
const [error, setError] = useState(
|
|
||||||
props.field.error ? props.field.error : ""
|
|
||||||
);
|
|
||||||
const [blurred, setBlurred] = useState(false);
|
|
||||||
const [simpleSelectOptions, setSimpleSelectOptions] = useState(
|
|
||||||
props.field.options
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const storedData = localStorage.getItem("dynamicField");
|
|
||||||
if (storedData) {
|
|
||||||
setStorageData(JSON.parse(storedData));
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const updateKey = (name, newKey, newLabel) => {
|
|
||||||
const newData = [...storageData];
|
|
||||||
|
|
||||||
const dataIndex = newData.findIndex((item) => item.name === name);
|
|
||||||
|
|
||||||
if (dataIndex !== -1) {
|
|
||||||
newData[dataIndex].key = newKey;
|
|
||||||
newData[dataIndex].label = newLabel;
|
|
||||||
} else {
|
|
||||||
newData.push({ name, key: newKey, label: newLabel });
|
|
||||||
}
|
|
||||||
|
|
||||||
setStorageData(newData);
|
|
||||||
// Update local storage with the new data
|
|
||||||
localStorage.setItem("dynamicField", JSON.stringify(newData));
|
|
||||||
};
|
|
||||||
|
|
||||||
const changeField = async (e) => {
|
|
||||||
if (e != undefined && e != null) {
|
|
||||||
updateKey(name, e.key, e.label);
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let handleOnChange = (e) => {
|
|
||||||
setValue(e.target.value);
|
|
||||||
if (blurred) {
|
|
||||||
setError(validateField(e.target.value, type, label));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleChange = () => {
|
|
||||||
const newChecked = !isChecked;
|
|
||||||
setIsChecked(newChecked);
|
|
||||||
if (blurred) {
|
|
||||||
setError(validateField(newChecked, type, label));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleaAutocompleteChange = (newValue, inputName) => {
|
|
||||||
setValue(newValue);
|
|
||||||
if (blurred) {
|
|
||||||
setError(validateField(newValue.target.value, type, label));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleBlur = (e) => {
|
|
||||||
setBlurred(true);
|
|
||||||
setError(validateField(value, type, label));
|
|
||||||
setError(
|
|
||||||
validateField(type === "checkbox" ? isChecked : value, type, label)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Validate the field when blurred
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFocus = () => {
|
|
||||||
setBlurred(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderError = () => {
|
|
||||||
// Check if validation is required for this field
|
|
||||||
const isValidationRequired = required || false;
|
|
||||||
|
|
||||||
if (isValidationRequired && error && blurred) {
|
|
||||||
return <FormHelperText error>{error}</FormHelperText>;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
function formatDate(inputDate) {
|
|
||||||
const date = new Date(inputDate);
|
|
||||||
const year = date.getFullYear();
|
|
||||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
||||||
const day = String(date.getDate()).padStart(2, "0");
|
|
||||||
const hours = String(date.getHours()).padStart(2, "0");
|
|
||||||
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
||||||
|
|
||||||
return `${year}-${month}-${day}T${hours}:${minutes}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case "select":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<CustomAutocomplete
|
|
||||||
apiUrl={searchApi}
|
|
||||||
displayKey={searchOptionHook}
|
|
||||||
valueKey={optionKey}
|
|
||||||
inputName={name}
|
|
||||||
onValueChange={() => {}}
|
|
||||||
variant={varient}
|
|
||||||
label={fieldLabel}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
onFocus={handleFocus}
|
|
||||||
/>
|
|
||||||
{renderError()}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "simple-select":
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<_Autocomplete
|
|
||||||
globalConfig={props.globalConfig}
|
|
||||||
token={props.token}
|
|
||||||
apiUrl=""
|
|
||||||
displayKey="label"
|
|
||||||
valueKey="type"
|
|
||||||
inputName={name}
|
|
||||||
onValueChange={handleaAutocompleteChange}
|
|
||||||
variant={varient}
|
|
||||||
label={label}
|
|
||||||
defaultObj={defaultObj}
|
|
||||||
options={simpleSelectOptions}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
onFocus={handleFocus}
|
|
||||||
/>
|
|
||||||
{renderError()}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case "advance-select":
|
|
||||||
return (
|
|
||||||
<div style={{ position: "relative" }}>
|
|
||||||
<_Autocomplete
|
|
||||||
globalConfig={props.globalConfig}
|
|
||||||
token={props.token}
|
|
||||||
apiUrl={searchApi}
|
|
||||||
displayKey={searchOptionHook}
|
|
||||||
valueKey={optionKey}
|
|
||||||
inputName={name}
|
|
||||||
onValueChange={handleaAutocompleteChange}
|
|
||||||
variant={varient}
|
|
||||||
label={fieldLabel}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
onFocus={handleFocus}
|
|
||||||
defaultObj={defaultObj}
|
|
||||||
/>
|
|
||||||
{renderError()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "checkbox":
|
|
||||||
return (
|
|
||||||
<div onBlur={handleBlur} onFocus={handleFocus}>
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Checkbox checked={isChecked} onChange={handleChange} />}
|
|
||||||
label={fieldLabel}
|
|
||||||
name={name}
|
|
||||||
/>
|
|
||||||
{renderError()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
case "datetime-local":
|
|
||||||
return (
|
|
||||||
<div style={{ textAlign: "left" }}>
|
|
||||||
<TextField
|
|
||||||
name={name}
|
|
||||||
label={fieldLabel}
|
|
||||||
type={type}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
variant={varient}
|
|
||||||
placeholder={placeholder}
|
|
||||||
value={formatDate(value)}
|
|
||||||
onChange={handleOnChange}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
onFocus={handleFocus}
|
|
||||||
/>
|
|
||||||
{renderError()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return (
|
|
||||||
<div style={{ position: "relative" }}>
|
|
||||||
<TextField
|
|
||||||
name={name}
|
|
||||||
label={fieldLabel}
|
|
||||||
type={type}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
variant={varient}
|
|
||||||
placeholder={placeholder}
|
|
||||||
value={value}
|
|
||||||
onChange={handleOnChange}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
onFocus={handleFocus}
|
|
||||||
/>
|
|
||||||
{renderError()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FormField;
|
|
|
@ -1,77 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import { Button } from "@mui/material";
|
|
||||||
import Drawer from "@mui/material/Drawer";
|
|
||||||
import Form from "./Form";
|
|
||||||
|
|
||||||
const FormWithDrawer = (props) => {
|
|
||||||
const [state, setState] = React.useState({
|
|
||||||
top: false,
|
|
||||||
left: false,
|
|
||||||
bottom: false,
|
|
||||||
right: false,
|
|
||||||
});
|
|
||||||
const toggleDrawer = (anchor, open) => (event) => {
|
|
||||||
if (
|
|
||||||
event.type === "keydown" &&
|
|
||||||
(event.key === "Tab" || event.key === "Shift")
|
|
||||||
) {
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setState({ ...state, [anchor]: open });
|
|
||||||
};
|
|
||||||
|
|
||||||
const anchor = props.anchor ? props.anchor : "right";
|
|
||||||
const actionBtnName = props.actionBtnName;
|
|
||||||
const data = props.data;
|
|
||||||
const buttonVarient = props.buttonVarient ? props.buttonVarient : "contained";
|
|
||||||
const updateFormTitle = props.updateFormTitle ? props.updateFormTitle : "";
|
|
||||||
const createFormTitle = props.createFormTitle ? props.createFormTitle : "";
|
|
||||||
const submitBtnTitle = props.submitBtnTitle ? props.submitBtnTitle : "Submit";
|
|
||||||
const handleCloseDrawer = () => {
|
|
||||||
setState({ ...state, [anchor]: false });
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<React.Fragment key={anchor}>
|
|
||||||
<Button
|
|
||||||
onClick={toggleDrawer(anchor, true)}
|
|
||||||
variant={buttonVarient}
|
|
||||||
style={props.buttonStyle}
|
|
||||||
>
|
|
||||||
{actionBtnName}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Drawer
|
|
||||||
anchor={anchor}
|
|
||||||
open={state[anchor]}
|
|
||||||
onClose={toggleDrawer(anchor, false)}
|
|
||||||
>
|
|
||||||
<div className="row" style={{ width: "470px" }}>
|
|
||||||
<div
|
|
||||||
className="col-md-12"
|
|
||||||
style={{ textAlign: "center", color: "#333", padding: "10px" }}
|
|
||||||
>
|
|
||||||
<h4>{createFormTitle}</h4>
|
|
||||||
<h4>{updateFormTitle}</h4>
|
|
||||||
<hr />
|
|
||||||
<div>
|
|
||||||
<Form
|
|
||||||
globalConfig={props.globalConfig}
|
|
||||||
token={props.token}
|
|
||||||
closeDrawer={handleCloseDrawer}
|
|
||||||
refreshData={() => props.refreshData()}
|
|
||||||
submitBtnTitle={submitBtnTitle}
|
|
||||||
inputFields={props.inputFields}
|
|
||||||
api={props.api}
|
|
||||||
data={data}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Drawer>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FormWithDrawer;
|
|
|
@ -1,57 +0,0 @@
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import AutoCompleteField from "./AutoCompleteField";
|
|
||||||
import FormField from "./FormField";
|
|
||||||
|
|
||||||
const MultiSelect = (props) => {
|
|
||||||
const [hookObj, setHookObj] = useState([]);
|
|
||||||
|
|
||||||
let handleOnChange = (key, value) => {
|
|
||||||
let obj = [];
|
|
||||||
console.log("Field Changed sfsdfds", key, value);
|
|
||||||
localStorage.setItem(key, value);
|
|
||||||
// setHookObj(hookObj => [...hookObj,{"name":key, "value":value}]);
|
|
||||||
console.log("Multi Dtaa", hookObj);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
let loadWithUpdatedApi = (field)=>{
|
|
||||||
// field.search.api=localStorage.getItem(field.search.hook) ;
|
|
||||||
console.log("Sub Search Hook",field.search.hook);
|
|
||||||
field.search.api = `http://127.0.0.1:8000/api/v1/getAllGroupsJoinedByUser/${localStorage.getItem(field.search.hook)}/`;
|
|
||||||
return(<FormField
|
|
||||||
FormField
|
|
||||||
handleChange={(name, value) => handleOnChange(name, value)}
|
|
||||||
field={field}
|
|
||||||
/>)
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(()=>{
|
|
||||||
|
|
||||||
},[])
|
|
||||||
let updateRefresh = (refresh)=>{
|
|
||||||
console.log(refresh);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<code>{JSON.stringify(props.field)}</code>
|
|
||||||
|
|
||||||
{props.field.map((f) => {
|
|
||||||
return f.search.hook ? (
|
|
||||||
loadWithUpdatedApi(f)
|
|
||||||
|
|
||||||
) : (
|
|
||||||
<FormField
|
|
||||||
FormField
|
|
||||||
handleChange={(name, value) => handleOnChange(name, value)}
|
|
||||||
refresh={(refresh) => updateRefresh(refresh)}
|
|
||||||
field={f}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default MultiSelect;
|
|
|
@ -1,98 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import { Button } from "@mui/material";
|
|
||||||
import "./style.css";
|
|
||||||
|
|
||||||
function Pagination({
|
|
||||||
nextPage,
|
|
||||||
previousPage,
|
|
||||||
makeApiRequest,
|
|
||||||
getValueFromUrl,
|
|
||||||
totalCount,
|
|
||||||
rowsPerPage,
|
|
||||||
currentPage,
|
|
||||||
setCurrentPage,
|
|
||||||
dataApi,
|
|
||||||
}) {
|
|
||||||
const totalPages = Math.ceil(totalCount / rowsPerPage);
|
|
||||||
|
|
||||||
const generatePageNumbers = () => {
|
|
||||||
const pages = [];
|
|
||||||
const maxPages = 4;
|
|
||||||
const currentPageIndex = currentPage;
|
|
||||||
|
|
||||||
let startPage = Math.max(1, currentPageIndex - Math.floor(maxPages / 2));
|
|
||||||
let endPage = Math.min(totalPages, startPage + maxPages - 1);
|
|
||||||
|
|
||||||
if (endPage === totalPages) {
|
|
||||||
startPage = Math.max(1, endPage - maxPages + 1);
|
|
||||||
} else if (startPage === 1) {
|
|
||||||
endPage = Math.min(totalPages, startPage + maxPages - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = startPage; i <= endPage; i++) {
|
|
||||||
pages.push(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pages;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePreviousClick = () => {
|
|
||||||
if (previousPage) {
|
|
||||||
const previousPageNumber = currentPage - 1;
|
|
||||||
setCurrentPage(previousPageNumber);
|
|
||||||
makeApiRequest(previousPage);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNextClick = () => {
|
|
||||||
if (nextPage) {
|
|
||||||
const nextPageNumber = currentPage + 1;
|
|
||||||
setCurrentPage(nextPageNumber);
|
|
||||||
makeApiRequest(nextPage);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="pagination-container">
|
|
||||||
<Button
|
|
||||||
disabled={!previousPage}
|
|
||||||
onClick={handlePreviousClick}
|
|
||||||
variant="outlined"
|
|
||||||
className="pagination-button"
|
|
||||||
style={{ margin: "5px" }}
|
|
||||||
>
|
|
||||||
Previous
|
|
||||||
</Button>
|
|
||||||
{generatePageNumbers().map((page) => (
|
|
||||||
<Button
|
|
||||||
key={page}
|
|
||||||
onClick={() => {
|
|
||||||
setCurrentPage(page);
|
|
||||||
const apiPage = nextPage
|
|
||||||
? `${nextPage.split("page=")[0]}page=${page}`
|
|
||||||
: `${dataApi}?page=${page}`;
|
|
||||||
makeApiRequest(apiPage);
|
|
||||||
}}
|
|
||||||
variant="outlined"
|
|
||||||
className={`pagination-button ${
|
|
||||||
currentPage === page ? "active-page" : ""
|
|
||||||
}`}
|
|
||||||
style={{ margin: "5px" }}
|
|
||||||
>
|
|
||||||
{page}
|
|
||||||
</Button>
|
|
||||||
))}
|
|
||||||
<Button
|
|
||||||
disabled={!nextPage}
|
|
||||||
onClick={handleNextClick}
|
|
||||||
variant="outlined"
|
|
||||||
className="pagination-button"
|
|
||||||
style={{ margin: "5px" }}
|
|
||||||
>
|
|
||||||
Next
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Pagination;
|
|
|
@ -1,33 +0,0 @@
|
||||||
import * as React from "react";
|
|
||||||
import Radio from "@mui/material/Radio";
|
|
||||||
import RadioGroup from "@mui/material/RadioGroup";
|
|
||||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
|
||||||
import FormControl from "@mui/material/FormControl";
|
|
||||||
import FormLabel from "@mui/material/FormLabel";
|
|
||||||
|
|
||||||
export default function RadioButtonsGroup() {
|
|
||||||
return (
|
|
||||||
<FormControl>
|
|
||||||
<FormLabel id="demo-radio-buttons-group-label">Payment In For </FormLabel>
|
|
||||||
<RadioGroup
|
|
||||||
aria-labelledby="demo-radio-buttons-group-label"
|
|
||||||
defaultValue="subscription_amt"
|
|
||||||
name="transaction_type"
|
|
||||||
row
|
|
||||||
>
|
|
||||||
<FormControlLabel
|
|
||||||
value="subscription_amt"
|
|
||||||
control={<Radio />}
|
|
||||||
label="Subscription"
|
|
||||||
/>
|
|
||||||
{/* <FormControlLabel value="penalty" control={<Radio />} label="Penalty" /> */}
|
|
||||||
<FormControlLabel
|
|
||||||
value="draw_winner"
|
|
||||||
control={<Radio />}
|
|
||||||
label="Draw Winner"
|
|
||||||
/>
|
|
||||||
{/* <FormControlLabel value="custom_amt" control={<Radio />} label="Custom Amount" /> */}
|
|
||||||
</RadioGroup>
|
|
||||||
</FormControl>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
import { Button } from '@mui/material';
|
|
||||||
import React from 'react'
|
|
||||||
import EditRow from './EditRow';
|
|
||||||
import FormWithDrawer from './FormWithDrawer';
|
|
||||||
function TableRow(props) {
|
|
||||||
var row = [];
|
|
||||||
const readBlock = (props.readBlock) ? props.readBlock : [];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function getCellArray() {
|
|
||||||
Object.keys(props.data).forEach((key) => {
|
|
||||||
console.log(readBlock);
|
|
||||||
if (!Object.values(readBlock).includes(key)) {
|
|
||||||
Object.entries(props.data).forEach((entry) => {
|
|
||||||
if (key === entry[0]) {
|
|
||||||
row.push(entry[1]);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function removeRow() { }
|
|
||||||
getCellArray();
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<tr>
|
|
||||||
{
|
|
||||||
row.map((data, index) => {
|
|
||||||
return <td key={index}>{data}</td>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
{(props.manage) ? <>
|
|
||||||
<td>
|
|
||||||
<Button onClick={() => removeRow()}> Delete</Button>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
<FormWithDrawer actionBtnName="Edit Data" inputFields={{}} api="https://api.udaymotors.in/api/v1/role/" />
|
|
||||||
{/* <EditRow data={props.data} /> */}
|
|
||||||
</td>
|
|
||||||
</> : ""
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default TableRow
|
|
|
@ -1,105 +0,0 @@
|
||||||
{
|
|
||||||
"api":"https://api.udaymotors.in/api/v1/group/"
|
|
||||||
,
|
|
||||||
"showField":[
|
|
||||||
{ "label": "Group Name", "key": "title" },
|
|
||||||
{ "label": "Description", "key": "description" },
|
|
||||||
{ "label": "Subscription Amount", "key": "subscription_amt" },
|
|
||||||
{ "label": "Max Allowed Users", "key": "max_users" },
|
|
||||||
{ "label": "Penalty Amount", "key": "penalty_amt" },
|
|
||||||
{ "label": "Start Date", "key": "start_date" },
|
|
||||||
{ "label": "End Date", "key": "end_date" }
|
|
||||||
],
|
|
||||||
"createField":[
|
|
||||||
|
|
||||||
{
|
|
||||||
"label": "Group name",
|
|
||||||
"type": "text",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "title"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Group Description",
|
|
||||||
"type": "text",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "description"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Start Date",
|
|
||||||
"type": "datetime-local",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "start_date"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "End Date",
|
|
||||||
"type": "datetime-local",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "end_date"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Max Users",
|
|
||||||
"type": "text",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "max_users"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Subscription Amount",
|
|
||||||
"type": "text",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "subscription_amt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Panelty Amount",
|
|
||||||
"type": "text",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "penalty_amt"
|
|
||||||
}
|
|
||||||
|
|
||||||
],
|
|
||||||
"editField":[
|
|
||||||
|
|
||||||
{
|
|
||||||
"label": "Group name",
|
|
||||||
"type": "text",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "title"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Group Description",
|
|
||||||
"type": "text",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "description"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Start Date",
|
|
||||||
"type": "datetime-local",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "start_date"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "End Date",
|
|
||||||
"type": "datetime-local",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "end_date"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Max Users",
|
|
||||||
"type": "text",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "max_users"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Subscription Amount",
|
|
||||||
"type": "text",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "subscription_amt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Panelty Amount",
|
|
||||||
"type": "text",
|
|
||||||
"variant": "standard",
|
|
||||||
"name": "penalty_amt"
|
|
||||||
}
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
export function camelCase(str) {
|
|
||||||
// Using replace method with regEx
|
|
||||||
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) {
|
|
||||||
return index === 0 ? word.toLowerCase() : word.toUpperCase();
|
|
||||||
}).replace(/\s+/g, '');
|
|
||||||
}
|
|
||||||
export function firstUpperCase(str) {
|
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
||||||
}
|
|
||||||
export const validateEmail = (email) => {
|
|
||||||
const emailRegex = /^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,}$/;
|
|
||||||
return emailRegex.test(email);
|
|
||||||
};
|
|
||||||
export const validatePassword = (password) => {
|
|
||||||
return password.length >= 8;
|
|
||||||
};
|
|
|
@ -1,46 +0,0 @@
|
||||||
.dynamic-form-element {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-table {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding-top: 15px;
|
|
||||||
padding-bottom: 15px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-input-table {
|
|
||||||
padding: 8px;
|
|
||||||
border: none; /* Remove border */
|
|
||||||
border-radius: 15px;
|
|
||||||
outline: none;
|
|
||||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
font-size: 16px;
|
|
||||||
width: 100%;
|
|
||||||
height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-input-table:focus {
|
|
||||||
background-color: #f0f0f0; /* Optional: Change background color on focus */
|
|
||||||
}
|
|
||||||
/* pagination */
|
|
||||||
.pagination-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination-button {
|
|
||||||
margin: 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination-button.active-page {
|
|
||||||
background-color: #6c757d;
|
|
||||||
color: rgb(73, 198, 207);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const useAPIManager = (globalConfig, _token) => {
|
|
||||||
const authToken = _token;
|
|
||||||
const global = globalConfig;
|
|
||||||
|
|
||||||
let token = authToken.access;
|
|
||||||
let authorization = _token
|
|
||||||
? {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
|
|
||||||
const getAPI = (API_NAME) => global.api.host + global.api[API_NAME];
|
|
||||||
|
|
||||||
const getHost = () => global.api.host;
|
|
||||||
|
|
||||||
const Post = async (api, payload) => {
|
|
||||||
let _api = getAPI(api).includes("undefined") ? api : getAPI(api);
|
|
||||||
try {
|
|
||||||
const response = await axios.post(_api, payload, authorization);
|
|
||||||
return response;
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Put = async (api, id, payload) => {
|
|
||||||
let _api = getAPI(api).includes("undefined") ? api : getAPI(api);
|
|
||||||
try {
|
|
||||||
const response = await axios.put(`${_api}${id}/`, payload, authorization);
|
|
||||||
return response;
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Patch = async (api, id, payload) => {
|
|
||||||
let _api = getAPI(api).includes("undefined") ? api : getAPI(api);
|
|
||||||
try {
|
|
||||||
const response = await axios.patch(
|
|
||||||
`${_api}${id}/`,
|
|
||||||
payload,
|
|
||||||
authorization
|
|
||||||
);
|
|
||||||
return response;
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Get = async (api) => {
|
|
||||||
let _api = getAPI(api).includes("undefined") ? api : getAPI(api);
|
|
||||||
try {
|
|
||||||
const response = await axios.get(_api, authorization);
|
|
||||||
return response.data;
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Delete = async (api, id) => {
|
|
||||||
let _api = getAPI(api).includes("undefined") ? api : getAPI(api);
|
|
||||||
try {
|
|
||||||
const response = await axios.delete(`${_api}${id}/`, authorization);
|
|
||||||
return response;
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return { Post, Put, Patch, Get, Delete, getAPI, getHost };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useAPIManager;
|
|
|
@ -1,89 +0,0 @@
|
||||||
// useApi.js
|
|
||||||
import { useContext } from 'react';
|
|
||||||
import axios from 'axios';
|
|
||||||
import AuthContext from '../auth/AuthContext';
|
|
||||||
import global from '../global/GlobalJSON.json';
|
|
||||||
|
|
||||||
|
|
||||||
const useApi = () => {
|
|
||||||
const { authToken } = useContext(AuthContext);
|
|
||||||
|
|
||||||
const getAPI = (API_NAME) => global.api.host + global.api[API_NAME];
|
|
||||||
|
|
||||||
const getHost = () => global.api.host;
|
|
||||||
let token = authToken.access;
|
|
||||||
|
|
||||||
const Post = async (api, payload) => {
|
|
||||||
let _api =(getAPI(api).includes('undefined'))?api:getAPI(api);
|
|
||||||
try {
|
|
||||||
const response = await axios.post(_api, payload, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return response;
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Put = async (api, id, payload) => {
|
|
||||||
let _api =(getAPI(api).includes('undefined'))?api:getAPI(api);
|
|
||||||
try {
|
|
||||||
const response = await axios.put(`${_api}${id}/`, payload, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return response;
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Patch = async (api, id, payload) => {
|
|
||||||
let _api =(getAPI(api).includes('undefined'))?api:getAPI(api);
|
|
||||||
try {
|
|
||||||
const response = await axios.patch(`${_api}${id}/`, payload, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return response;
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Get = async (api) => {
|
|
||||||
let _api =(getAPI(api).includes('undefined'))?api:getAPI(api);
|
|
||||||
try {
|
|
||||||
const response = await axios.get(_api, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return response.data;
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Delete = async (api, id) => {
|
|
||||||
let _api =(getAPI(api).includes('undefined'))?api:getAPI(api);
|
|
||||||
try {
|
|
||||||
const response = await axios.delete(`${_api}${id}/`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return response;
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return { Post, Put, Patch, Get, Delete, getAPI, getHost };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useApi;
|
|
Before Width: | Height: | Size: 186 KiB |
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 169 KiB |
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import config from "../global/GlobalJSON.json";
|
import config from "../../config/Global.json";
|
||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
const {
|
const {
|
||||||
api: { version },
|
api: { version },
|
|
@ -1,4 +1,7 @@
|
||||||
import React, { useContext, useState } from 'react';
|
import React, { useContext, useState } from 'react';
|
||||||
|
import { Link, useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AppBar,
|
AppBar,
|
||||||
Toolbar,
|
Toolbar,
|
||||||
|
@ -14,8 +17,8 @@ import {
|
||||||
Collapse,
|
Collapse,
|
||||||
Divider,
|
Divider,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Link, useLocation } from 'react-router-dom';
|
|
||||||
import AuthContext from '../auth/AuthContext';
|
|
||||||
import {
|
import {
|
||||||
Menu as MenuIcon,
|
Menu as MenuIcon,
|
||||||
ChevronLeft as ChevronLeftIcon,
|
ChevronLeft as ChevronLeftIcon,
|
||||||
|
@ -24,11 +27,7 @@ import {
|
||||||
ExpandMore,
|
ExpandMore,
|
||||||
Home as HomeIcon,
|
Home as HomeIcon,
|
||||||
People as PeopleIcon,
|
People as PeopleIcon,
|
||||||
CalendarToday as CalendarTodayIcon,
|
|
||||||
AccountBalance as AccountBalanceIcon,
|
AccountBalance as AccountBalanceIcon,
|
||||||
Receipt as ReceiptIcon,
|
|
||||||
Paid as PaidIcon,
|
|
||||||
TimeToLeave as LeaveIcon,
|
|
||||||
Settings as SettingsIcon,
|
Settings as SettingsIcon,
|
||||||
Help as HelpIcon,
|
Help as HelpIcon,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
|
@ -36,6 +35,10 @@ import { styled, useTheme } from '@mui/material/styles';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faUserCircle } from '@fortawesome/free-solid-svg-icons';
|
import { faUserCircle } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
|
||||||
|
import AuthContext from '../../utils/auth/AuthContext';
|
||||||
|
|
||||||
|
|
||||||
const drawerWidth = 240;
|
const drawerWidth = 240;
|
||||||
|
|
||||||
const Main = styled('main', { shouldForwardProp: (prop) => prop !== 'open' })(
|
const Main = styled('main', { shouldForwardProp: (prop) => prop !== 'open' })(
|
||||||
|
@ -141,7 +144,7 @@ const Header = () => {
|
||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1 }}>
|
<Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1 }}>
|
||||||
HbaseApp
|
React-Placeholder
|
||||||
</Typography>
|
</Typography>
|
||||||
<IconButton edge="end" color="inherit" onClick={handleMenuOpen}>
|
<IconButton edge="end" color="inherit" onClick={handleMenuOpen}>
|
||||||
<FontAwesomeIcon icon={faUserCircle} />
|
<FontAwesomeIcon icon={faUserCircle} />
|
||||||
|
@ -195,13 +198,13 @@ const Header = () => {
|
||||||
<ListItemStyled
|
<ListItemStyled
|
||||||
button
|
button
|
||||||
component={Link}
|
component={Link}
|
||||||
to="/company"
|
to="/api-manager-starter"
|
||||||
onClick={handleNavClick}
|
onClick={handleNavClick}
|
||||||
sx={{ pl: 4 }}
|
sx={{ pl: 4 }}
|
||||||
className={location.pathname === '/company' ? 'active' : ''}
|
className={location.pathname === '/api-manager-starter' ? 'active' : ''}
|
||||||
>
|
>
|
||||||
<AccountBalanceIcon style={{ marginRight: '10px' }} />
|
<AccountBalanceIcon style={{ marginRight: '10px' }} />
|
||||||
<ListItemText primary="Company" />
|
<ListItemText primary="Api Manager Starter" />
|
||||||
</ListItemStyled>
|
</ListItemStyled>
|
||||||
<ListItemStyled
|
<ListItemStyled
|
||||||
button
|
button
|
||||||
|
@ -209,10 +212,10 @@ const Header = () => {
|
||||||
to="/department"
|
to="/department"
|
||||||
onClick={handleNavClick}
|
onClick={handleNavClick}
|
||||||
sx={{ pl: 4 }}
|
sx={{ pl: 4 }}
|
||||||
className={location.pathname === '/department' ? 'active' : ''}
|
className={location.pathname === '/page2' ? 'active' : ''}
|
||||||
>
|
>
|
||||||
<PeopleIcon style={{ marginRight: '10px' }} />
|
<PeopleIcon style={{ marginRight: '10px' }} />
|
||||||
<ListItemText primary="Department" />
|
<ListItemText primary="Page2" />
|
||||||
</ListItemStyled>
|
</ListItemStyled>
|
||||||
<ListItemStyled
|
<ListItemStyled
|
||||||
button
|
button
|
||||||
|
@ -220,10 +223,10 @@ const Header = () => {
|
||||||
to="/employee"
|
to="/employee"
|
||||||
onClick={handleNavClick}
|
onClick={handleNavClick}
|
||||||
sx={{ pl: 4 }}
|
sx={{ pl: 4 }}
|
||||||
className={location.pathname === '/employee' ? 'active' : ''}
|
className={location.pathname === '/page3' ? 'active' : ''}
|
||||||
>
|
>
|
||||||
<PeopleIcon style={{ marginRight: '10px' }} />
|
<PeopleIcon style={{ marginRight: '10px' }} />
|
||||||
<ListItemText primary="Employee" />
|
<ListItemText primary="Page3" />
|
||||||
</ListItemStyled>
|
</ListItemStyled>
|
||||||
|
|
||||||
</List>
|
</List>
|
|
@ -1,216 +0,0 @@
|
||||||
// import React, { useState, useContext, useEffect } from "react";
|
|
||||||
// import {
|
|
||||||
// AppBar,
|
|
||||||
// Toolbar,
|
|
||||||
// Typography,
|
|
||||||
// Box,
|
|
||||||
// IconButton,
|
|
||||||
// Menu,
|
|
||||||
// MenuItem,
|
|
||||||
// useMediaQuery,
|
|
||||||
// Drawer,
|
|
||||||
// List,
|
|
||||||
// ListItem,
|
|
||||||
// ListItemText,
|
|
||||||
// } from "@mui/material";
|
|
||||||
// import { Link } from "react-router-dom";
|
|
||||||
// import AccountCircle from "@mui/icons-material/AccountCircle";
|
|
||||||
// import MenuIcon from "@mui/icons-material/Menu";
|
|
||||||
// import AuthContext from "../auth/AuthContext";
|
|
||||||
// import useApi from "../api-manager/useApi";
|
|
||||||
// import UserTypeUpdatePassword from "../utils/userTypePassword";
|
|
||||||
|
|
||||||
|
|
||||||
// const Header = () => {
|
|
||||||
// const { user, logOutUser } = useContext(AuthContext);
|
|
||||||
// const [profile, setProfile] = useState(null);
|
|
||||||
// const [userType, setUserType] = useState(null);
|
|
||||||
// const [companyName, setCompanyName] = useState("");
|
|
||||||
// const [companyId, setCompanyId] = useState(null);
|
|
||||||
// const [dialogOpen, setDialogOpen] = useState(false);
|
|
||||||
// const { Get, Post, getHost } = useApi();
|
|
||||||
// const isMobile = useMediaQuery("(max-width:600px)");
|
|
||||||
// const [drawerOpen, setDrawerOpen] = useState(false);
|
|
||||||
|
|
||||||
// const handleClose = () => {
|
|
||||||
// setProfile(null);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const handleMenu = (event) => {
|
|
||||||
// setProfile(event.currentTarget);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const toggleDrawer = (open) => (event) => {
|
|
||||||
// if (
|
|
||||||
// event.type === "keydown" &&
|
|
||||||
// (event.key === "Tab" || event.key === "Shift")
|
|
||||||
// ) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// setDrawerOpen(open);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const getUserType = async () => {
|
|
||||||
// try {
|
|
||||||
// const userTypeData = await Get("checkUserType");
|
|
||||||
// setUserType(userTypeData.user_type);
|
|
||||||
|
|
||||||
// const compId = await Get(
|
|
||||||
// `${getHost()}/api/v1/getCompanyByUserOrDeptId?user_id=${user.user_id}`
|
|
||||||
// );
|
|
||||||
// setCompanyName(compId.company_name);
|
|
||||||
// setCompanyId(compId.company_id);
|
|
||||||
// } catch (error) {
|
|
||||||
// setCompanyName("Hey Admin");
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// getUserType();
|
|
||||||
// }, []);
|
|
||||||
|
|
||||||
// const renderLinks = () => {
|
|
||||||
// switch (userType) {
|
|
||||||
// case "department user":
|
|
||||||
// return [
|
|
||||||
// { path: "/", label: "Home" },
|
|
||||||
// { path: "/cheque-form", label: "Print Cheque" },
|
|
||||||
// { path: "/history", label: "Cheque History" },
|
|
||||||
// ];
|
|
||||||
// case "company user":
|
|
||||||
// return [
|
|
||||||
// { path: "/", label: "Home" },
|
|
||||||
// { path: "/cheque-form", label: "Print Cheque" },
|
|
||||||
// { path: "/history", label: "Cheque History" },
|
|
||||||
// { path: "/department", label: "Departments" },
|
|
||||||
// ];
|
|
||||||
// case "superuser":
|
|
||||||
// return [
|
|
||||||
// { path: "/", label: "Humbingo Home" },
|
|
||||||
// { path: "/company", label: "Company" },
|
|
||||||
// { path: "/AdminDepartment", label: "Departments" },
|
|
||||||
// { path: "/licence", label: "Licence" },
|
|
||||||
// { path: "/registree", label: "Registree" },
|
|
||||||
// { path: "/user", label: "User" },
|
|
||||||
// { path: "/role", label: "Role" },
|
|
||||||
// { path: "/history", label: "Cheque History" },
|
|
||||||
// ];
|
|
||||||
// default:
|
|
||||||
// return [];
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const linkStyle = {
|
|
||||||
// color: "inherit",
|
|
||||||
// textDecoration: "none",
|
|
||||||
// margin: "0 10px",
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const drawerLinks = (
|
|
||||||
// <Box
|
|
||||||
// sx={{ width: 250 }}
|
|
||||||
// role="presentation"
|
|
||||||
// onClick={toggleDrawer(false)}
|
|
||||||
// onKeyDown={toggleDrawer(false)}
|
|
||||||
// >
|
|
||||||
// <List>
|
|
||||||
// {renderLinks().map((link, index) => (
|
|
||||||
// <ListItem button component={Link} to={link.path} key={index}>
|
|
||||||
// <ListItemText primary={link.label} />
|
|
||||||
// </ListItem>
|
|
||||||
// ))}
|
|
||||||
// </List>
|
|
||||||
// </Box>
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const handlePasswordSubmit = async (newPassword) => {
|
|
||||||
// try {
|
|
||||||
// await Post(
|
|
||||||
// `${getHost()}/api/v1/updatePassword/company/${companyId}/`,
|
|
||||||
// { password: newPassword }
|
|
||||||
// );
|
|
||||||
// alert("Password updated successfully"); // Replace with a better toast notification if needed
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error("Error changing password:", error);
|
|
||||||
// alert("Failed to update password"); // Replace with a better toast notification if needed
|
|
||||||
// }
|
|
||||||
// setDialogOpen(false);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <AppBar position="sticky" sx={{ backgroundColor: "#021526" }}>
|
|
||||||
// <Toolbar>
|
|
||||||
// <IconButton
|
|
||||||
// edge="start"
|
|
||||||
// color="inherit"
|
|
||||||
// aria-label="menu"
|
|
||||||
// onClick={toggleDrawer(true)}
|
|
||||||
// sx={{ display: isMobile ? "block" : "none" }}
|
|
||||||
// >
|
|
||||||
// <MenuIcon />
|
|
||||||
// </IconButton>
|
|
||||||
// <Typography
|
|
||||||
// variant="h6"
|
|
||||||
// sx={{ flexGrow: 1, display: "flex", alignItems: "center" }}
|
|
||||||
// >
|
|
||||||
// <img
|
|
||||||
// src="https://humbingo.com/wp-content/uploads/2024/06/Logo-32-.webp"
|
|
||||||
// height="50px"
|
|
||||||
// alt="Logo"
|
|
||||||
// />
|
|
||||||
// {!isMobile && (
|
|
||||||
// <span style={{ marginLeft: "10px" }}>{companyName}</span>
|
|
||||||
// )}
|
|
||||||
// </Typography>
|
|
||||||
// {!isMobile && (
|
|
||||||
// <Box sx={{ display: "flex" }}>
|
|
||||||
// {renderLinks().map((link, index) => (
|
|
||||||
// <Link to={link.path} style={linkStyle} key={index}>
|
|
||||||
// {link.label}
|
|
||||||
// </Link>
|
|
||||||
// ))}
|
|
||||||
// </Box>
|
|
||||||
// )}
|
|
||||||
// <IconButton
|
|
||||||
// edge="end"
|
|
||||||
// aria-label="account of current user"
|
|
||||||
// aria-haspopup="true"
|
|
||||||
// onClick={handleMenu}
|
|
||||||
// color="inherit"
|
|
||||||
// >
|
|
||||||
// <AccountCircle />
|
|
||||||
// </IconButton>
|
|
||||||
// <Menu
|
|
||||||
// anchorEl={profile}
|
|
||||||
// anchorOrigin={{
|
|
||||||
// vertical: "bottom",
|
|
||||||
// horizontal: "left",
|
|
||||||
// }}
|
|
||||||
// keepMounted
|
|
||||||
// transformOrigin={{
|
|
||||||
// vertical: "top",
|
|
||||||
// horizontal: "left",
|
|
||||||
// }}
|
|
||||||
// open={Boolean(profile)}
|
|
||||||
// onClose={handleClose}
|
|
||||||
// >
|
|
||||||
// {/* <MenuItem onClick={handleClose}>{`Hello, ${user.user_id}`}</MenuItem> */}
|
|
||||||
// <MenuItem onClick={() => setDialogOpen(true)}>Change Password</MenuItem>
|
|
||||||
// <MenuItem onClick={logOutUser} ><span style={{backgroundColor: "#f60002", color: "White", textAlign:"center",padding: "7px", width: "100%", borderRadius: "5px"}}>Logout</span></MenuItem>
|
|
||||||
// </Menu>
|
|
||||||
// </Toolbar>
|
|
||||||
// <Drawer anchor="left" open={drawerOpen} onClose={toggleDrawer(false)}>
|
|
||||||
// {drawerLinks}
|
|
||||||
// </Drawer>
|
|
||||||
// <UserTypeUpdatePassword
|
|
||||||
// open={dialogOpen}
|
|
||||||
// onClose={() => setDialogOpen(false)}
|
|
||||||
// onSubmit={handlePasswordSubmit}
|
|
||||||
// userType={userType}
|
|
||||||
// companyId={companyId}
|
|
||||||
// />
|
|
||||||
// </AppBar>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export default Header;
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import React, { useContext } from "react";
|
||||||
|
import APIManager from "../external/api-manager/APIManager";
|
||||||
|
import global from "../../config/Global.json";
|
||||||
|
import AuthContext from "../../utils/auth/AuthContext";
|
||||||
|
import schema from "./Schema/APIManagerStarter.json";
|
||||||
|
const APIManagerStarter = () => {
|
||||||
|
let { authToken } = useContext(AuthContext);
|
||||||
|
return (
|
||||||
|
<div className="container">
|
||||||
|
<APIManager
|
||||||
|
globalConfig={global}
|
||||||
|
token={authToken}
|
||||||
|
data={schema}
|
||||||
|
createRequired={false}
|
||||||
|
editRequired={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default APIManagerStarter
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useContext, useEffect, useState } from "react";
|
import React, { useContext, useEffect, useState } from "react";
|
||||||
import AuthContext from "../../../auth/AuthContext";
|
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
|
import AuthContext from "../../utils/auth/AuthContext";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Container,
|
Container,
|
||||||
TextField,
|
TextField,
|
||||||
|
@ -12,7 +13,7 @@ import {
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { Visibility, VisibilityOff } from "@mui/icons-material";
|
import { Visibility, VisibilityOff } from "@mui/icons-material";
|
||||||
import logo from "../../../logo.png"
|
import logo from "../../assets/img/logo.png"
|
||||||
|
|
||||||
const LoginPage = () => {
|
const LoginPage = () => {
|
||||||
let { loginUser } = useContext(AuthContext);
|
let { loginUser } = useContext(AuthContext);
|
|
@ -0,0 +1,79 @@
|
||||||
|
{
|
||||||
|
"api": "company",
|
||||||
|
"showField": [
|
||||||
|
{ "label": "Name", "key": "name" },
|
||||||
|
{ "label": "Address", "key": "address" },
|
||||||
|
{ "label": "Contact Number", "key": "contact_no" },
|
||||||
|
{ "label": "Email", "key": "email" },
|
||||||
|
{ "label": "Website", "key": "website" }
|
||||||
|
],
|
||||||
|
"createField": [
|
||||||
|
{
|
||||||
|
"label": "Name",
|
||||||
|
"type": "text",
|
||||||
|
"varient": "standard",
|
||||||
|
"name": "name",
|
||||||
|
"required":true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Address",
|
||||||
|
"type": "text",
|
||||||
|
"varient": "standard",
|
||||||
|
"name": "address",
|
||||||
|
"required":true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Contact Number",
|
||||||
|
"type": "number",
|
||||||
|
"varient": "standard",
|
||||||
|
"name": "contact_no",
|
||||||
|
"required":true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Email",
|
||||||
|
"type": "email",
|
||||||
|
"varient": "standard",
|
||||||
|
"name": "email",
|
||||||
|
"required":true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Website",
|
||||||
|
"type": "text",
|
||||||
|
"varient": "standard",
|
||||||
|
"name": "website"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"editField": [
|
||||||
|
{
|
||||||
|
"label": "Name",
|
||||||
|
"type": "text",
|
||||||
|
"varient": "standard",
|
||||||
|
"name": "name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Address",
|
||||||
|
"type": "text",
|
||||||
|
"varient": "standard",
|
||||||
|
"name": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Contact Number",
|
||||||
|
"type": "number",
|
||||||
|
"varient": "standard",
|
||||||
|
"name": "contact_no"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Email",
|
||||||
|
"type": "email",
|
||||||
|
"varient": "standard",
|
||||||
|
"name": "email"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Website",
|
||||||
|
"type": "text",
|
||||||
|
"varient": "standard",
|
||||||
|
"name": "website"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import global from "../global/GlobalJSON.json"
|
import global from "./Global.json"
|
||||||
|
|
||||||
export function getAPI(API_NAME) {
|
export function getAPI(API_NAME) {
|
||||||
return global.api.host + global.api[API_NAME];
|
return global.api.host + global.api[API_NAME];
|
|
@ -1,12 +1,15 @@
|
||||||
{
|
{
|
||||||
"api": {
|
"api": {
|
||||||
"host": "https://cheque-api.humbingo.in",
|
"host": "https://dev_api_cheque.humbingo.in",
|
||||||
"token": "/auth/token/",
|
"token": "/auth/token/",
|
||||||
"refreshToken": "/auth/token/refresh/",
|
"refreshToken": "/auth/token/refresh/",
|
||||||
"user": "/api/v1/user/",
|
"user": "/api/v1/user/",
|
||||||
"role": "/api/v1/role/",
|
"role": "/api/v1/role/",
|
||||||
"permission": "/api/v1/permission/",
|
"permission": "/api/v1/permission/",
|
||||||
"checkUserType": "/api/v1/checkUserType",
|
"checkUserType": "/api/v1/checkUserType",
|
||||||
|
"company":"/api/v1/company",
|
||||||
|
"test":"api/v1/test/",
|
||||||
|
|
||||||
"version": "1.0"
|
"version": "1.0"
|
||||||
},
|
},
|
||||||
"debug": true
|
"debug": true
|
|
@ -1,13 +0,0 @@
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
||||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
||||||
sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
|
||||||
monospace;
|
|
||||||
}
|
|
|
@ -1,17 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import './index.css';
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import reportWebVitals from './reportWebVitals';
|
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
|
||||||
<App />
|
<App />
|
||||||
</React.StrictMode>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
|
||||||
// to log results (for example: reportWebVitals(console.log))
|
|
||||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
|
||||||
reportWebVitals();
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
|
Before Width: | Height: | Size: 2.6 KiB |
|
@ -1,13 +0,0 @@
|
||||||
const reportWebVitals = onPerfEntry => {
|
|
||||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
|
||||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
|
||||||
getCLS(onPerfEntry);
|
|
||||||
getFID(onPerfEntry);
|
|
||||||
getFCP(onPerfEntry);
|
|
||||||
getLCP(onPerfEntry);
|
|
||||||
getTTFB(onPerfEntry);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default reportWebVitals;
|
|
|
@ -1,5 +0,0 @@
|
||||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
|
||||||
// allows you to do things like:
|
|
||||||
// expect(element).toHaveTextContent(/react/i)
|
|
||||||
// learn more: https://github.com/testing-library/jest-dom
|
|
||||||
import '@testing-library/jest-dom';
|
|
|
@ -1,9 +1,12 @@
|
||||||
import { createContext, useEffect, useState } from "react";
|
import { createContext, useEffect, useState } from "react";
|
||||||
import axios from "axios";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import {jwtDecode} from "jwt-decode"; // Make sure jwt-decode is imported correctly
|
|
||||||
import { getAPI } from "../global/Global"; // Make sure this function is properly defined
|
import axios from "axios";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
import {jwtDecode} from "jwt-decode"; // Make sure jwt-decode is imported correctly
|
||||||
|
|
||||||
|
import { getAPI } from "../../config/Global"; // Make sure this function is properly defined
|
||||||
|
|
||||||
|
|
||||||
const AuthContext = createContext();
|
const AuthContext = createContext();
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import {useContext } from "react"
|
import {useContext } from "react"
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import AuthContext from "../auth/AuthContext";
|
import AuthContext from "./AuthContext";
|
||||||
import LoginPage from "../pages/UI/login/login";
|
import LoginPage from "../../components/pages/Login";
|
||||||
import Header from "../components/header";
|
import Header from "../../components/common/Header";
|
||||||
|
|
||||||
|
|
||||||
|
|