justforsake
This commit is contained in:
parent
33147c8b0e
commit
95108241f2
4
.env
4
.env
|
|
@ -1,4 +1,4 @@
|
|||
# VITE_REACT_APP_BACKEND_URL="https://sandbox.exampaper.vidh.ai"
|
||||
# VITE_REACT_APP_BACKEND_URL="http://localhost:9999"
|
||||
VITE_REACT_APP_BACKEND_URL="http://localhost:9999"
|
||||
METABASE_BASE_URL="http://metabase.usln.in/public/question/d8774923-09bb-4cd9-903b-559d417e12cf"
|
||||
VITE_REACT_APP_BACKEND_URL="https://api.exampaper.vidh.ai"
|
||||
# VITE_REACT_APP_BACKEND_URL="https://api.exampaper.vidh.ai"
|
||||
|
|
@ -15,6 +15,7 @@ import Statistics from "./Components/Statistics";
|
|||
import AnomolyAttendencePage from "./Components/AnomolyAttendencePage";
|
||||
import AttendenceAdditionalRecord from "./Components/AttendenceAdditionalRecord";
|
||||
import AttendenceAdditionalRecordCorrection from "./Components/AttendenceAdditionalRecordCorrection";
|
||||
import QueryExecutor from "./Components/QueryExecutor";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
|
|
@ -22,6 +23,7 @@ function App() {
|
|||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />}></Route>
|
||||
<Route path="/sqlPlayground" element={<QueryExecutor/>}></Route>
|
||||
<Route
|
||||
path="/anomoly/attendence/reassigned"
|
||||
element={<AnomolyReassigned />}
|
||||
|
|
|
|||
|
|
@ -106,17 +106,34 @@ const PartACorrection = () => {
|
|||
const examDateInputRef = useRef(null);
|
||||
const studentNameInputRef = useRef(null);
|
||||
const bookletInputRef = useRef(null);
|
||||
const registerNumberInputRef = useRef(null);
|
||||
|
||||
// Handle the Enter key press in the register number input
|
||||
const handleRegisterNumberKeyDown = (e) => {
|
||||
console.log("Handle register number key down ....")
|
||||
if (e.key === 'Enter') {
|
||||
console.log("Entering subject code field ...")
|
||||
// Focus on the subject code input
|
||||
registerNumberInputRef.current.unfocus()
|
||||
const subjectCodeInput = subjectCodeInputRef.current;
|
||||
console.log("Subject code input :: ",subjectCodeInput)
|
||||
subjectCodeInput.focus();
|
||||
subjectCodeInput.select();
|
||||
}
|
||||
};
|
||||
|
||||
const handleBookletSerialNoKeyDown = (e) =>{
|
||||
console.log("Handdle booklet serial no key down.....")
|
||||
if(e.key === 'Enter'){
|
||||
console.log("Entering register number field...")
|
||||
const registerNumberInputField = registerNumberInputRef.current
|
||||
console.log("Register number input :: ",registerNumberInputField)
|
||||
registerNumberInputField.focus()
|
||||
// const ele = document.getElementById("corrected-register-number-input")
|
||||
// console.log("ELE : ",ele)
|
||||
// ele.focus()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
|
@ -460,6 +477,7 @@ const PartACorrection = () => {
|
|||
};
|
||||
|
||||
const updatePartAanomoly = async (e) => {
|
||||
subjectCodeInputRef.current.blur()
|
||||
setIsLoading(true);
|
||||
setMetaBaseRegnoLink(null);
|
||||
setMetaBaseSubjectLinkWithTitle(null);
|
||||
|
|
@ -768,7 +786,7 @@ const PartACorrection = () => {
|
|||
/>
|
||||
</Box>
|
||||
</Box> */}
|
||||
{showSubjectTitleInput && (
|
||||
{/* {showSubjectTitleInput && (
|
||||
<Box className="d-flex flex-column align-items-start gap-2 py-2">
|
||||
<label for="corrected-register-number-input">
|
||||
Corrected Subject Title:
|
||||
|
|
@ -785,10 +803,10 @@ const PartACorrection = () => {
|
|||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
)} */}
|
||||
{showAdditionalStudentInputs && (
|
||||
<>
|
||||
<Box className="d-flex flex-column align-items-start gap-2 py-2">
|
||||
{/* <Box className="d-flex flex-column align-items-start gap-2 py-2">
|
||||
<label for="corrected-register-number-input">
|
||||
Corrected Exam Centre Code:
|
||||
</label>
|
||||
|
|
@ -806,8 +824,8 @@ const PartACorrection = () => {
|
|||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box className="d-flex flex-column align-items-start gap-2 py-2">
|
||||
</Box> */}
|
||||
{/* <Box className="d-flex flex-column align-items-start gap-2 py-2">
|
||||
<label for="corrected-register-number-input">
|
||||
Corrected Exam Date:
|
||||
</label>
|
||||
|
|
@ -824,8 +842,8 @@ const PartACorrection = () => {
|
|||
placeholder="(DD-MM-YYYY)"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box className="d-flex flex-column align-items-start gap-2 py-2">
|
||||
</Box> */}
|
||||
{/* <Box className="d-flex flex-column align-items-start gap-2 py-2">
|
||||
<label for="corrected-register-number-input">
|
||||
Corrected Student Name:
|
||||
</label>
|
||||
|
|
@ -841,7 +859,7 @@ const PartACorrection = () => {
|
|||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box> */}
|
||||
{batchType === "old" && (
|
||||
<Box className="d-flex flex-column align-items-start gap-2 py-2">
|
||||
<label for="corrected-register-number-input">
|
||||
|
|
@ -854,6 +872,7 @@ const PartACorrection = () => {
|
|||
value={correctedSerialNo}
|
||||
inputRef={bookletInputRef}
|
||||
autoComplete="off"
|
||||
onKeyDown={handleBookletSerialNoKeyDown}
|
||||
onChange={(e) => {
|
||||
setCorrectedSerialNo(e.target.value);
|
||||
}}
|
||||
|
|
@ -874,6 +893,7 @@ const PartACorrection = () => {
|
|||
id="corrected-register-number-input"
|
||||
className="w-100"
|
||||
value={correctedRegisterNo}
|
||||
inputRef={registerNumberInputRef}
|
||||
autoComplete="off"
|
||||
onKeyDown={handleRegisterNumberKeyDown} // Attach the keydown handler
|
||||
onChange={(e) => {
|
||||
|
|
@ -980,7 +1000,7 @@ const PartACorrection = () => {
|
|||
/>
|
||||
</Box>
|
||||
</Box> */}
|
||||
{showSubjectTitleInput && (
|
||||
{/* {showSubjectTitleInput && (
|
||||
<Box className="d-flex flex-column align-items-start gap-2 py-2">
|
||||
<label for="corrected-register-number-input">
|
||||
Corrected Subject Title:
|
||||
|
|
@ -997,10 +1017,10 @@ const PartACorrection = () => {
|
|||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
)} */}
|
||||
{showAdditionalStudentInputs && (
|
||||
<>
|
||||
<Box className="d-flex flex-column align-items-start gap-2 py-2">
|
||||
{/* <Box className="d-flex flex-column align-items-start gap-2 py-2">
|
||||
<label for="corrected-register-number-input">
|
||||
Corrected Exam Centre Code:
|
||||
</label>
|
||||
|
|
@ -1050,7 +1070,7 @@ const PartACorrection = () => {
|
|||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box> */}
|
||||
<Box className="d-flex flex-column align-items-start gap-2 py-2">
|
||||
<label for="corrected-register-number-input">
|
||||
Corrected Booklet Serial No:
|
||||
|
|
@ -1060,6 +1080,7 @@ const PartACorrection = () => {
|
|||
id="corrected-register-number-input"
|
||||
className="w-100"
|
||||
value={correctedSerialNo}
|
||||
onKeyDown={handleBookletSerialNoKeyDown}
|
||||
autoComplete="off"
|
||||
onChange={(e) => {
|
||||
setCorrectedSerialNo(e.target.value);
|
||||
|
|
@ -1081,6 +1102,8 @@ const PartACorrection = () => {
|
|||
className="w-100"
|
||||
value={correctedRegisterNo}
|
||||
autoComplete="off"
|
||||
inputRef={registerNumberInputRef}
|
||||
onKeyDown={handleRegisterNumberKeyDown}
|
||||
onChange={(e) => {
|
||||
setCorrectedRegisterNo(e.target.value);
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,339 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import {
|
||||
DesktopOutlined,
|
||||
FileOutlined,
|
||||
PieChartOutlined,
|
||||
TeamOutlined,
|
||||
UserOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { Breadcrumb, Layout, Menu, Typography, theme } from "antd";
|
||||
import { ToastContainer, toast } from "react-toastify";
|
||||
import { Box, Button } from "@mui/material";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import EditButton from "./EditButton";
|
||||
import { width } from "@mui/system";
|
||||
import "react-toastify/dist/ReactToastify.css";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import LoadingContainer from "./LoadingContainer";
|
||||
import HomeIcon from "@mui/icons-material/Home";
|
||||
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import QueryStatsIcon from "@mui/icons-material/QueryStats";
|
||||
import RotateLeftIcon from "@mui/icons-material/RotateLeft";
|
||||
import RotateRightIcon from "@mui/icons-material/RotateRight";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import {
|
||||
updatePartAanomolyData,
|
||||
updateSystemNo,
|
||||
} from "../redux/actions/actions";
|
||||
import SimpleDialog from "./SimpleDialog";
|
||||
import SystemNumberDialog from "./SystemNumberDialog";
|
||||
import ValidationContainer from "./ValidationContainer";
|
||||
|
||||
const { Header, Content, Footer, Sider } = Layout;
|
||||
const QueryExecutor = () => {
|
||||
const [responseData, setResponseData] = useState([]);
|
||||
const [totalData, setTotalData] = useState([]);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [totalPages, setTotalPages] = useState(0);
|
||||
const [imageColumn, setImageColumn] = useState(null);
|
||||
const [query, setQuery] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [limit, setLimit] = useState("");
|
||||
const recordsPerPage = 5;
|
||||
|
||||
const {
|
||||
token: { colorBgContainer, borderRadiusLG },
|
||||
} = theme.useToken();
|
||||
|
||||
const fetchQueryValue = async () => {
|
||||
if (query.includes("limit")) {
|
||||
alert("Please specify the limit in the input field.");
|
||||
return;
|
||||
}
|
||||
if (query.includes(";")) {
|
||||
alert("Please remove the special character from the query ';'");
|
||||
return;
|
||||
}
|
||||
if (!limit) {
|
||||
alert("Limit cannot be empty !!");
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
const payload = {
|
||||
query: query,
|
||||
limit: limit,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${import.meta.env.VITE_REACT_APP_BACKEND_URL}/fetchQueryValue`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
}
|
||||
);
|
||||
const data = await response.json();
|
||||
setIsLoading(false);
|
||||
if (data.status === "success") {
|
||||
setTotalData(data.results);
|
||||
const totalPageCount = Math.ceil(data.results.length / recordsPerPage);
|
||||
setTotalPages(totalPageCount);
|
||||
setCurrentPage(1);
|
||||
setResponseData(data.results.slice(0, recordsPerPage));
|
||||
} else {
|
||||
toast.error(data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (totalData.length > 0) {
|
||||
const startIndex = (currentPage - 1) * recordsPerPage;
|
||||
const endIndex = startIndex + recordsPerPage;
|
||||
setResponseData(totalData.slice(startIndex, endIndex));
|
||||
}
|
||||
}, [currentPage, totalData]);
|
||||
|
||||
const getTableData = () => {
|
||||
if (responseData.length === 0) return null;
|
||||
const keys = Object.keys(totalData[0]);
|
||||
|
||||
return (
|
||||
<div className="w-100">
|
||||
<div className="text-left d-flex justify-content-between align-items-center">
|
||||
<h5>
|
||||
<strong>Total Results </strong> : {totalData.length}
|
||||
</h5>
|
||||
{totalData.length > 0 && (
|
||||
<div id="footer-container">
|
||||
<div
|
||||
id="footer-main"
|
||||
className="d-flex justify-content-center p-3 align-items-center"
|
||||
>
|
||||
<div className="d-flex justify-content-center align-items-center p-1">
|
||||
<strong>{currentPage}</strong>/<strong>{totalPages}</strong>
|
||||
</div>
|
||||
<div className="d-flex gap-3">
|
||||
<button
|
||||
className="btn text-light bg-primary rounded p-2 mx-3"
|
||||
onClick={() =>
|
||||
setCurrentPage((prev) => Math.max(prev - 1, 1))
|
||||
}
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<button
|
||||
className="btn text-light bg-primary rounded p-2"
|
||||
onClick={() =>
|
||||
setCurrentPage((prev) => Math.min(prev + 1, totalPages))
|
||||
}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="my-2 overflow-auto">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>sno</th>
|
||||
<th>Record Info</th>
|
||||
<th>Image</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{responseData.map((value, index) => {
|
||||
const sno = totalData.indexOf(value) + 1;
|
||||
let recordInfo = "";
|
||||
let imageInfo = "";
|
||||
|
||||
keys.forEach((header) => {
|
||||
if (header !== imageColumn) {
|
||||
recordInfo += `<p><strong>${header}</strong>: ${value[header]}</p>`;
|
||||
} else {
|
||||
imageInfo = (
|
||||
<td key={header}>
|
||||
<img
|
||||
src={`https://docs.exampaper.vidh.ai/${value[header]}`}
|
||||
width="900px"
|
||||
height="auto"
|
||||
alt={header}
|
||||
/>
|
||||
</td>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<tr key={index}>
|
||||
<td>{sno}</td>
|
||||
<td>
|
||||
<div
|
||||
className="d-flex flex-column p-2"
|
||||
dangerouslySetInnerHTML={{ __html: recordInfo }}
|
||||
></div>
|
||||
</td>
|
||||
{imageInfo}
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout
|
||||
style={{
|
||||
minHeight: "100vh",
|
||||
}}
|
||||
>
|
||||
<ToastContainer />
|
||||
<Layout>
|
||||
<Header
|
||||
style={{
|
||||
padding: 0,
|
||||
background: colorBgContainer,
|
||||
}}
|
||||
>
|
||||
<Box className="d-flex justify-content-between h-100 py-1 px-2">
|
||||
<Button
|
||||
className="bg-primary p-1 text-light"
|
||||
onClick={() => {
|
||||
navigate(-1);
|
||||
}}
|
||||
>
|
||||
<ArrowBackIcon />
|
||||
</Button>
|
||||
<Box className="d-flex justify-content-between gap-2">
|
||||
{/* <Button
|
||||
className="bg-primary p-1 text-light"
|
||||
onClick={() => {
|
||||
navigate("/anomoly/reassigned/stats");
|
||||
}}
|
||||
>
|
||||
<QueryStatsIcon />
|
||||
</Button> */}
|
||||
<Box className="d-flex justify-content-between gap-md-4 gap-1 align-items-center">
|
||||
<Button
|
||||
className="bg-primary p-1 text-light rounded h-100"
|
||||
onClick={() => {
|
||||
navigate("/");
|
||||
}}
|
||||
>
|
||||
<HomeIcon />
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Header>
|
||||
<Content
|
||||
style={{
|
||||
margin: "16px 16px",
|
||||
}}
|
||||
>
|
||||
<div className="mx-3">
|
||||
<div className="my-3 d-flex flex-md-row flex-column">
|
||||
<div className="w-100 w-md-75">
|
||||
<textarea
|
||||
className="w-100 p-3 h5"
|
||||
id="text-area-input"
|
||||
placeholder="Enter your query ...."
|
||||
rows="5"
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
></textarea>
|
||||
</div>
|
||||
<div className="d-none d-md-block w-25">
|
||||
<div className="w-100 d-flex flex-column gap-2 mx-2">
|
||||
<input
|
||||
className="rounded p-2 h6"
|
||||
type="text"
|
||||
placeholder="Limit"
|
||||
id="limit-input"
|
||||
autoComplete="off"
|
||||
value={limit}
|
||||
onChange={(e) => setLimit(e.target.value)}
|
||||
/>
|
||||
<input
|
||||
className="input rounded p-2 h6"
|
||||
type="text"
|
||||
placeholder="Image column name"
|
||||
id="image-column-input"
|
||||
autoComplete="off"
|
||||
value={imageColumn}
|
||||
onChange={(e) => setImageColumn(e.target.value)}
|
||||
/>
|
||||
<button
|
||||
className="btn bg-primary text-light"
|
||||
id="submit-btn"
|
||||
onClick={fetchQueryValue}
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="d-block d-md-none w-100">
|
||||
<div className="w-100 d-flex flex-column gap-2 mx-2">
|
||||
<input
|
||||
className="rounded p-2 h6"
|
||||
type="text"
|
||||
placeholder="Limit"
|
||||
id="limit-input"
|
||||
autoComplete="off"
|
||||
value={limit}
|
||||
onChange={(e) => setLimit(e.target.value)}
|
||||
/>
|
||||
<input
|
||||
className="input rounded p-2 h6"
|
||||
type="text"
|
||||
placeholder="Image column name"
|
||||
id="image-column-input"
|
||||
autoComplete="off"
|
||||
value={imageColumn}
|
||||
onChange={(e) => setImageColumn(e.target.value)}
|
||||
/>
|
||||
<button
|
||||
className="btn bg-primary text-light"
|
||||
id="submit-btn"
|
||||
onClick={fetchQueryValue}
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="results-container"
|
||||
className="d-flex w-100 justify-content-center"
|
||||
>
|
||||
{getTableData()}
|
||||
</div>
|
||||
</div>
|
||||
</Content>
|
||||
<Footer
|
||||
style={{
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
exampaper.vidh.ai ©{new Date().getFullYear()}
|
||||
</Footer>
|
||||
</Layout>
|
||||
{isLoading && <LoadingContainer loadingText={"Loading"} />}
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default QueryExecutor;
|
||||
|
|
@ -66,3 +66,21 @@ button:focus-visible {
|
|||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border: 1px solid black !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
padding: 5px;
|
||||
border: 1px solid black !important;
|
||||
text-align: left;
|
||||
}
|
||||
Loading…
Reference in New Issue