This commit is contained in:
Pradeeppon01 2024-06-11 18:18:19 +05:30
parent 174910e6aa
commit 6614046568
26 changed files with 3128 additions and 510 deletions

3
.env
View File

@ -1 +1,4 @@
# VITE_REACT_APP_BACKEND_URL="https://sandbox.exampaper.vidh.ai"
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"

1
.gitignore vendored
View File

@ -11,6 +11,7 @@ node_modules
dist
dist-ssr
*.local
*.zip
# Editor directories and files
.vscode/*

BIN
dist_jun11.zip Normal file

Binary file not shown.

BIN
dist_jun9.zip Normal file

Binary file not shown.

111
package-lock.json generated
View File

@ -18,8 +18,12 @@
"react": "^18.2.0",
"react-bootstrap": "^2.10.2",
"react-dom": "^18.2.0",
"react-medium-image-zoom": "^5.2.4",
"react-redux": "^9.1.2",
"react-router-dom": "^6.23.1",
"react-toastify": "^10.0.5"
"react-toastify": "^10.0.5",
"react-zoom-pan-pinch": "^3.4.4",
"redux": "^5.0.1"
},
"devDependencies": {
"@types/react": "^18.2.66",
@ -1961,6 +1965,11 @@
"@types/react": "*"
}
},
"node_modules/@types/use-sync-external-store": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
},
"node_modules/@types/warning": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
@ -5175,6 +5184,43 @@
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"node_modules/react-medium-image-zoom": {
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/react-medium-image-zoom/-/react-medium-image-zoom-5.2.4.tgz",
"integrity": "sha512-XLu/fLqpbmhiDAGA6yie78tDv4kh8GxvS7kKQArSOvCvm5zvgItoh4h01NAAvnezQ60ovsTeedHiHG3eG9CcGg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/rpearce"
}
],
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-redux": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz",
"integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==",
"dependencies": {
"@types/use-sync-external-store": "^0.0.3",
"use-sync-external-store": "^1.0.0"
},
"peerDependencies": {
"@types/react": "^18.2.25",
"react": "^18.0",
"redux": "^5.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"redux": {
"optional": true
}
}
},
"node_modules/react-refresh": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
@ -5241,6 +5287,24 @@
"react-dom": ">=16.6.0"
}
},
"node_modules/react-zoom-pan-pinch": {
"version": "3.4.4",
"resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.4.4.tgz",
"integrity": "sha512-lGTu7D9lQpYEQ6sH+NSlLA7gicgKRW8j+D/4HO1AbSV2POvKRFzdWQ8eI0r3xmOsl4dYQcY+teV6MhULeg1xBw==",
"engines": {
"node": ">=8",
"npm": ">=5"
},
"peerDependencies": {
"react": "*",
"react-dom": "*"
}
},
"node_modules/redux": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
@ -5874,6 +5938,14 @@
"punycode": "^2.1.0"
}
},
"node_modules/use-sync-external-store": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
"integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/vite": {
"version": "5.2.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz",
@ -7312,6 +7384,11 @@
"@types/react": "*"
}
},
"@types/use-sync-external-store": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
},
"@types/warning": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
@ -9599,6 +9676,21 @@
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"react-medium-image-zoom": {
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/react-medium-image-zoom/-/react-medium-image-zoom-5.2.4.tgz",
"integrity": "sha512-XLu/fLqpbmhiDAGA6yie78tDv4kh8GxvS7kKQArSOvCvm5zvgItoh4h01NAAvnezQ60ovsTeedHiHG3eG9CcGg==",
"requires": {}
},
"react-redux": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz",
"integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==",
"requires": {
"@types/use-sync-external-store": "^0.0.3",
"use-sync-external-store": "^1.0.0"
}
},
"react-refresh": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
@ -9641,6 +9733,17 @@
"prop-types": "^15.6.2"
}
},
"react-zoom-pan-pinch": {
"version": "3.4.4",
"resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.4.4.tgz",
"integrity": "sha512-lGTu7D9lQpYEQ6sH+NSlLA7gicgKRW8j+D/4HO1AbSV2POvKRFzdWQ8eI0r3xmOsl4dYQcY+teV6MhULeg1xBw==",
"requires": {}
},
"redux": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="
},
"reflect.getprototypeof": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
@ -10080,6 +10183,12 @@
"punycode": "^2.1.0"
}
},
"use-sync-external-store": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
"integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==",
"requires": {}
},
"vite": {
"version": "5.2.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz",

View File

@ -20,8 +20,12 @@
"react": "^18.2.0",
"react-bootstrap": "^2.10.2",
"react-dom": "^18.2.0",
"react-medium-image-zoom": "^5.2.4",
"react-redux": "^9.1.2",
"react-router-dom": "^6.23.1",
"react-toastify": "^10.0.5"
"react-toastify": "^10.0.5",
"react-zoom-pan-pinch": "^3.4.4",
"redux": "^5.0.1"
},
"devDependencies": {
"@types/react": "^18.2.66",

View File

@ -10,6 +10,8 @@ import ReassignedStats from "./Components/ReassignedStats";
import IndividualExamCentreStats from "./Components/IndividualExamCentreStats";
import PartAReassigned from "./Components/PartAReassigned";
import PartACorrection from "./Components/PartACorrection";
import Verification from "./Components/Verification";
import Statistics from "./Components/Statistics";
function App() {
return (
@ -36,15 +38,21 @@ function App() {
element={<IndividualExamCentreStats/>}
>
</Route>
{/* <Route
<Route
path="/anomoly/PartA"
element={<PartAReassigned/>}
>
</Route>
{/* <Route
path="/verification"
element={<Verification/>}
>
</Route> */}
<Route path="/statistics" element={<Statistics/>}></Route>
<Route path="/anomoly/partA/booklet"
element={<PartACorrection/>}
>
</Route> */}
</Route>
</Routes>
</BrowserRouter>
</>

View File

@ -22,6 +22,8 @@ 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 { updateAttendenceAnomolyData } from "../redux/actions/actions";
import { useDispatch, useSelector } from "react-redux";
const { Header, Content, Footer, Sider } = Layout;
function getItem(label, key, icon, children) {
@ -32,26 +34,24 @@ function getItem(label, key, icon, children) {
label,
};
}
// const items = [
// getItem('Option 1', '1', <PieChartOutlined />),
// getItem('Option 2', '2', <DesktopOutlined />),
// getItem('User', 'sub1', <UserOutlined />, [
// getItem('Tom', '3'),
// getItem('Bill', '4'),
// getItem('Alex', '5'),
// ]),
// getItem('Team', 'sub2', <TeamOutlined />, [getItem('Team 1', '6'), getItem('Team 2', '8')]),
// getItem('Files', '9', <FileOutlined />),
// ];
const items = [getItem("Reassigned Booklet No", "1", <PieChartOutlined />)];
const AnomolyReassigned = () => {
const [collapsed, setCollapsed] = useState(false);
const [anomolyData, setAnomolyData] = useState([]);
const [filteredAnomolyData,setFilterAnomolyData] = useState([])
const [tableRowData, setTableRowData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const [distinctExamCentreCodes,setDistinctExamCentreCodes] = useState([])
const dispatch = useDispatch();
const reduxAnomolyData = useSelector((state) => state.attendenceAnomolyData);
const [filterSelectedExamCentreCode,setFilterSelectedExamCentreCode] = useState("")
// Log Redux store state
console.log("Redux store state after dispatch:", reduxAnomolyData);
useEffect(() => {
const handleResize = () => {
@ -95,16 +95,41 @@ const AnomolyReassigned = () => {
};
}
useEffect(()=>{
const tmpData = [];
for (const data of anomolyData) {
tmpData.push(
createData(
data.attendence_serial_no,
data.student_slno,
data.exam_centre_code,
data.exam_centre,
data.student_name,
data.register_number,
data.reassigned_serial_no
)
);
}
console.log("Tmp data is : ", tmpData);
if (tmpData.length > 0) {
setTableRowData(tmpData);
}
},[anomolyData])
const fetchAnomalyData = () => {
console.log("Fetching.......");
setIsLoading(true);
fetch(`${import.meta.env.VITE_REACT_APP_BACKEND_URL}/fetchAnamolyAttendenceData`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
fetch(
`${
import.meta.env.VITE_REACT_APP_BACKEND_URL
}/fetchAnamolyAttendenceData`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
)
.then((response) => {
console.log("Response fetched..");
return response.json();
@ -113,25 +138,24 @@ const AnomolyReassigned = () => {
console.log("Response Data is : ", responseData);
setIsLoading(false);
if (responseData.status === "success") {
setAnomolyData(responseData.data);
const tmpData = [];
for (const data of responseData.data) {
tmpData.push(
createData(
data.attendence_serial_no,
data.student_slno,
data.exam_centre_code,
data.exam_centre,
data.student_name,
data.register_number,
data.reassigned_serial_no
)
);
}
console.log("Tmp data is : ", tmpData);
if (tmpData.length > 0) {
setTableRowData(tmpData);
setAnomolyData(responseData?.data);
const tmpExamCentreCodes = [];
const distinctExamCentreCodesSet = new Set(distinctExamCentreCodes);
for (var data of responseData?.data) {
if (!distinctExamCentreCodesSet.has(data.exam_centre_code)) {
distinctExamCentreCodesSet.add(data.exam_centre_code);
tmpExamCentreCodes.push(data.exam_centre_code);
}
setFilterAnomolyData([...tmpExamCentreCodes])
}
setDistinctExamCentreCodes([...distinctExamCentreCodesSet]);
console.log("Tmp exam centre code: ", tmpExamCentreCodes);
// console.log("Data to be stored in store : ", responseData?.data);
dispatch(updateAttendenceAnomolyData(responseData?.data));
}
})
.catch((error) => {
@ -141,10 +165,28 @@ const AnomolyReassigned = () => {
};
useEffect(() => {
fetchAnomalyData();
if (reduxAnomolyData.length > 0) {
console.log("Redux anomoly data found")
setAnomolyData(reduxAnomolyData)
} else {
console.log("Redux anomoly data not found")
fetchAnomalyData();
}
}, []);
useEffect(()=>{
const tmpData = []
for(var data in anomolyData){
if(data?.exam_centre_code == filterSelectedExamCentreCode){
tmpData.push(data)
}
}
},[filterSelectedExamCentreCode])
const {
token: { colorBgContainer, borderRadiusLG },
} = theme.useToken();
@ -214,10 +256,18 @@ const AnomolyReassigned = () => {
<Box className="w-100 d-flex justify-content-center">
{tableRowData.length > 0 && (
<TableComponent
filterSelectedExamCentreCode = {filterSelectedExamCentreCode}
setFilterSelectedExamCentreCode = {setFilterSelectedExamCentreCode}
rows={tableRowData}
type={"AnomolyReassigned"}
distinctExamCentreCodes = {distinctExamCentreCodes}
/>
)}
{tableRowData.length == 0 && (
<Box className="w-100 d-flex justify-content-center py-2 align-items-center text-center">
<h6>No Data Found !!</h6>
</Box>
)}
</Box>
</Box>
</Content>

View File

@ -17,11 +17,14 @@ import { ToastContainer, toast } from "react-toastify";
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 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 QueryStatsIcon from "@mui/icons-material/QueryStats";
import { useDispatch, useSelector } from "react-redux";
import { updateAttendenceAnomolyData } from "../redux/actions/actions";
import RotateLeftIcon from "@mui/icons-material/RotateLeft";
import RotateRightIcon from "@mui/icons-material/RotateRight";
const { Header, Content, Footer, Sider } = Layout;
function getItem(label, key, icon, children) {
@ -47,6 +50,7 @@ function getItem(label, key, icon, children) {
const items = [getItem("Reassigned Booklet No", "1", <PieChartOutlined />)];
const AttendenceCorrection = () => {
console.log("Checking1 ...");
const [collapsed, setCollapsed] = useState(false);
const [bookletInput, setBookletInput] = useState(null);
const [dataFetched, setDataFetched] = useState(false);
@ -54,10 +58,29 @@ const AttendenceCorrection = () => {
const [updateReassigned, setUpdateReassigned] = useState(false);
const [reasssingedSno, setReassignedSno] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const navigate = useNavigate()
const [registerNumber, setRegisterNumber] = useState(null);
const [backgroundPosition, setBackgroundPosition] = useState("0% 0%");
const [zoomed, setZoomed] = useState(false);
const dispatch = useDispatch();
const [scaleWidthValue, setScaleWidthValue] = useState(80);
const [rotateValue, setRotateValue] = useState(0);
const reduxAnomolyData = useSelector((state) => state.attendenceAnomolyData);
// console.log("Anomoly Data is : ", reduxAnomolyData);
const [anomolyData, setAnomolyData] = useState([]);
const handleMouseMove = (e) => {
const { left, top, width, height } = e.target.getBoundingClientRect();
const x = ((e.pageX - left) / width) * 100;
const y = ((e.pageY - top) / height) * 100;
setBackgroundPosition(`${x}% ${y}%`);
setZoomed(true);
};
const navigate = useNavigate();
let [searchParams, setSearchParams] = useSearchParams();
const searchParamsBookletSerialNo = searchParams.get("sno");
console.log("Serach parmas sno : ", searchParamsBookletSerialNo);
// console.log("Serach parmas sno : ", searchParamsBookletSerialNo);
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
useEffect(() => {
@ -65,19 +88,19 @@ const AttendenceCorrection = () => {
setWindowWidth(window.innerWidth);
};
window.addEventListener('resize', handleResize);
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener('resize', handleResize);
window.removeEventListener("resize", handleResize);
};
}, []);
useEffect(() => {
if (windowWidth < 800) {
setCollapsed(true)
setCollapsed(true);
}
if(windowWidth > 800){
setCollapsed(false)
if (windowWidth > 800) {
setCollapsed(false);
}
}, [windowWidth]);
@ -91,29 +114,68 @@ const AttendenceCorrection = () => {
submitBookletInput();
}, [bookletInput]);
const {
token: { colorBgContainer, borderRadiusLG },
} = theme.useToken();
useEffect(() => {
if (reduxAnomolyData.length === 0) {
fetchAnomalyData();
}
}, []);
const fetchAnomalyData = () => {
console.log("Fetching.......");
setIsLoading(true);
fetch(
`${
import.meta.env.VITE_REACT_APP_BACKEND_URL
}/fetchAnamolyAttendenceData`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
)
.then((response) => {
console.log("Response fetched..");
return response.json();
})
.then((responseData) => {
console.log("Response Data is : ", responseData);
setIsLoading(false);
if (responseData.status === "success") {
setAnomolyData(responseData?.data);
console.log("Data to be stored in store : ", responseData?.data);
dispatch(updateAttendenceAnomolyData(responseData?.data));
}
})
.catch((error) => {
console.error("Error fetching data: ", error);
setIsLoading(false);
});
};
const submitBookletInput = async () => {
setIsLoading(true);
setStudentData(null);
if (!bookletInput) {
console.log("Returning");
return;
}
const payload = {
bookletInput,
};
const response = await fetch(`${import.meta.env.VITE_REACT_APP_BACKEND_URL}/fetchBookletInfo`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const response = await fetch(
`${import.meta.env.VITE_REACT_APP_BACKEND_URL}/fetchBookletInfo`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
}
);
const responseData = await response.json();
console.log("Response Data is : ", responseData);
setDataFetched(true);
@ -125,26 +187,133 @@ const AttendenceCorrection = () => {
}
if (responseData.data) {
setStudentData(responseData.data[0]);
const student_data = responseData.data[0];
setRegisterNumber(student_data?.register_number);
}
}
};
const url = `https://docs.exampaper.vidh.ai/${studentData?.s3_path}`;
// console.log("Url is : ", url);
const figureStyle = {
backgroundImage: `url(${url})`,
backgroundPosition: zoomed ? backgroundPosition : "center",
backgroundSize: zoomed ? "200%" : "cover",
height: "100%", // Adjust the height as needed
width: "60%", // Adjust the width as needed
border: "1px solid #ddd",
overflow: "hidden",
};
const ZoomInImage = () => {
console.log("Zooming In Image ....");
const elements = document.getElementsByClassName("scanned-img");
for (var ele of elements) {
console.log("Ele is : ", ele);
const newScaleWidthValue = scaleWidthValue + 10;
setScaleWidthValue(newScaleWidthValue);
// ele.style.transform = `scale(${newScaleValue})`;
ele.style.width = `${newScaleWidthValue}%`;
}
};
const ZoomOutImage = () => {
console.log("Zooming Out Image ....");
const elements = document.getElementsByClassName("scanned-img");
for (var ele of elements) {
console.log("Ele is : ", ele);
const newScaleWidthValue = scaleWidthValue - 10;
setScaleWidthValue(newScaleWidthValue);
// ele.style.transform = `scale(${newScaleValue})`;
ele.style.width = `${newScaleWidthValue}%`;
}
};
const RotateImageLeft = () => {
const elements = document.getElementsByClassName("scanned-img");
for (var ele of elements) {
console.log("Ele is : ", ele);
const newRotateValue = rotateValue - 90;
setRotateValue(newRotateValue);
ele.style.transform = `rotate(${newRotateValue}deg)`;
}
};
const RotateImageRight = () => {
const elements = document.getElementsByClassName("scanned-img");
for (var ele of elements) {
console.log("Ele is : ", ele);
const newRotateValue = rotateValue + 90;
setRotateValue(newRotateValue);
ele.style.transform = `rotate(${newRotateValue}deg)`;
}
};
const ImageStyle = {
// transform: `scale(${scaleValue})`,
transformOrigin: "left", // Adjust the zoom origin as needed
transition: "transform 0.2s ease-in-out",
};
const containerStyle = {
width: "auto", // Set the width and height as needed
maxHeight: "90%",
overflowX: "scroll",
position: "relative",
};
const handleMouseLeave = () => {
setBackgroundPosition("0% 0%");
setZoomed(false);
};
const updateReassignedSno = async () => {
setIsLoading(true);
// if(reduxAnomolyData.length === 0){
// console.log("Redux anomoly data length is 0.......")
// fetchAnomalyData()
// }
console.log("Reassgined Sno : ", reasssingedSno);
const payload = {
bookletInput,
reasssingedSno,
registerNumber,
};
const response = await fetch(`${import.meta.env.VITE_REACT_APP_BACKEND_URL}/updateReassingedSno`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const response = await fetch(
`${import.meta.env.VITE_REACT_APP_BACKEND_URL}/updateReassingedSno`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
}
);
const responseData = await response.json();
setIsLoading(false);
setReassignedSno(null);
if (responseData.status === "success" && responseData?.status_code == 200) {
console.log("Updation success");
toast.success("Record Updated Successfully !!");
var index = 0
var RecordIndex = 0
const filteredData = reduxAnomolyData.filter((data) => {
if (data?.student_slno === searchParamsBookletSerialNo) {
RecordIndex = index
console.log("data matched : ", data);
return false; // Return false to remove the matched item
}
index += 1
return true; // Keep the unmatched items
});
console.log("Filtered Data: ", filteredData);
dispatch(updateAttendenceAnomolyData(filteredData));
if (filteredData.length > 0) {
navigate(
`/anomoly/reassigned/booklet?sno=${filteredData[RecordIndex].student_slno}`
);
}
} else if (
responseData.status === "success" &&
responseData?.status_code == 405
@ -154,6 +323,45 @@ const AttendenceCorrection = () => {
}
};
const markAsAssigned = async () => {
setIsLoading(true);
const payload = { bookletInput };
const response = await fetch(
`${import.meta.env.VITE_REACT_APP_BACKEND_URL}/markAsAssigned`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
}
);
const responseData = await response.json();
setIsLoading(false);
if (responseData.status === "success") {
toast.success("Record Updated Successfully !!");
var index = 0
var RecordIndex = 0
const filteredData = reduxAnomolyData.filter((data) => {
if (data?.student_slno === searchParamsBookletSerialNo) {
RecordIndex = index
console.log("data matched : ", data);
return false; // Return false to remove the matched item
}
index += 1
return true; // Keep the unmatched items
});
console.log("Filtered Data: ", filteredData);
dispatch(updateAttendenceAnomolyData(filteredData));
if (filteredData.length > 0) {
navigate(
`/anomoly/reassigned/booklet?sno=${filteredData[RecordIndex].student_slno}`
);
}
}
};
return (
<Layout
style={{
@ -181,7 +389,7 @@ const AttendenceCorrection = () => {
background: colorBgContainer,
}}
>
<Box className="d-flex justify-content-between h-100 py-1 px-2">
<Box className="d-flex justify-content-between h-100 py-1 px-2">
<Button
className="bg-primary p-1 text-light"
onClick={() => {
@ -237,102 +445,96 @@ const AttendenceCorrection = () => {
<Box className="w-100 d-flex flex-column flex-md-row justify-content-between">
<Box className="w-25 d-none d-md-flex flex-column">
<Box className="d-flex justify-content-between">
<BookletInput
{/* <BookletInput
className="d-flex flex-1"
setBookletInput={setBookletInput}
bookletInput={bookletInput}
setDataFetched={setDataFetched}
/>
<Button
/> */}
{/* <Button
className="px-md-5 px-2 mx-1 mx-md-2 text-light bg-primary"
onClick={submitBookletInput}
>
Submit
</Button>
</Button> */}
</Box>
{!isLoading && !studentData && (
{/* {!isLoading && !studentData && (
<Box className="w-100 py-5">
<h6>Invalid Booklet Serial No !!</h6>
</Box>
)}
{dataFetched && studentData && (
)} */}
{studentData && (
<>
<Box>
<Box className="d-flex justify-content-start px-2 py-3">
<h6>Booklet Info:</h6>
<h6>
<u>Booklet Info:</u>
</h6>
</Box>
<Box className="px-2">
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="student-name-input">Student Name:</label>
<TextField
id="student-name-input"
disabled="true"
className="w-100"
value={studentData.student_name}
/>
</Box>
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="exam-centre-code-input">
Exam Center Code:
<label for="student-name-input" className="h6">
<u>Booklet Serial No:</u>
</label>
<TextField
id="exam-centre-code-input"
disabled="true"
className="w-100"
value={studentData.exam_centre_code}
/>
<h5>{bookletInput}</h5>
</Box>
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="exam-centre-input">Exam Centre:</label>
<TextField
id="exam-centre-input"
disabled="true"
className="w-100"
value={studentData.exam_centre}
/>
<label for="student-name-input" className="h6">
<u>Student Name:</u>
</label>
<h5>{studentData?.student_name}</h5>
</Box>
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="exam-date-input">Exam Date:</label>
<TextField
id="exam-date-input"
disabled="true"
className="w-100"
value={studentData.exam_date}
/>
<label for="exam-centre-code-input" className="h6">
<u>Exam Center Code:</u>
</label>
<h5>{studentData?.exam_centre_code}</h5>
</Box>
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="exam-centre-input" className="h6">
<u>Exam Centre:</u>
</label>
<h5>{studentData.exam_centre}</h5>
</Box>
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="exam-date-input" className="h6">
<u>Exam Date:</u>
</label>
<h5>{studentData?.exam_date}</h5>
</Box>
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="reassigned-serial-no-input">
Reassigned Serial No:
<u>Reassigned Serial No:</u>
</label>
<Box className="d-flex justify-content-between w-100">
<TextField
id="reassigned-serial-no-input"
disabled={!updateReassigned}
className="w-100"
value={studentData.reassigned_serial_no}
placeholder={`Please enter the SNo.${studentData?.rownumber} Answer Booklet No`}
autoComplete="off"
onChange={(e) => {
setReassignedSno(e.target.value);
}}
/>
<Button
onClick={() => {
setUpdateReassigned(!updateReassigned);
}}
>
<EditButton />
</Button>
</Box>
</Box>
<Box className="py-2 d-flex justify-content-start">
<Box className="py-2 d-flex justify-content-start flex-column gap-2">
<Button
className="text-light bg-primary p-3"
disabled={!updateReassigned}
className="text-light bg-primary p-3 w-100"
disabled={!reasssingedSno}
onClick={updateReassignedSno}
>
Update
</Button>
<Button
className="text-light bg-primary p-3 w-100"
onClick={markAsAssigned}
>
Mark As Assigned
</Button>
</Box>
</Box>
</Box>
@ -340,125 +542,163 @@ const AttendenceCorrection = () => {
)}
</Box>
<Box className="w-md-25 d-flex d-md-none flex-column">
<Box className="d-flex justify-content-between">
<BookletInput
className="d-flex flex-1"
setBookletInput={setBookletInput}
bookletInput={bookletInput}
setDataFetched={setDataFetched}
/>
<Button
className="px-md-5 px-2 mx-1 mx-md-2 text-light bg-primary"
onClick={submitBookletInput}
>
Submit
</Button>
</Box>
{!isLoading && !studentData && (
{/* {!isLoading && !studentData && (
<Box className="w-100 py-5">
<h6>Invalid Booklet Serial No !!</h6>
</Box>
)}
{dataFetched && studentData && (
)} */}
{studentData && (
<>
<Box>
<Box className="d-flex justify-content-start px-2 py-3">
<h6>Booklet Info:</h6>
<h6>
<u>Booklet Info:</u>
</h6>
</Box>
<Box className="px-2">
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="student-name-input">Student Name:</label>
<TextField
id="student-name-input"
disabled="true"
className="w-100"
value={studentData.student_name}
/>
</Box>
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="exam-centre-code-input">
Exam Center Code:
<label for="student-name-input" className="h6">
<u>Booklet Serial No:</u>
</label>
<TextField
id="exam-centre-code-input"
disabled="true"
className="w-100"
value={studentData.exam_centre_code}
/>
<h5>{bookletInput}</h5>
</Box>
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="exam-centre-input">Exam Centre:</label>
<TextField
id="exam-centre-input"
disabled="true"
className="w-100"
value={studentData.exam_centre}
/>
<label for="student-name-input" className="h6">
<u>Student Name:</u>
</label>
<h5>{studentData?.student_name}</h5>
</Box>
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="exam-date-input">Exam Date:</label>
<TextField
id="exam-date-input"
disabled="true"
className="w-100"
value={studentData.exam_date}
/>
<label for="exam-centre-code-input" className="h6">
<u>Exam Center Code:</u>
</label>
<h5>{studentData?.exam_centre_code}</h5>
</Box>
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="exam-centre-input" className="h6">
<u>Exam Centre:</u>
</label>
<h5>{studentData.exam_centre}</h5>
</Box>
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="exam-date-input" className="h6">
<u>Exam Date:</u>
</label>
<h5>{studentData?.exam_date}</h5>
</Box>
<Box className="d-flex flex-column align-items-start gap-2 py-2">
<label for="reassigned-serial-no-input">
Reassigned Serial No:
<u>Reassigned Serial No:</u>
</label>
<Box className="d-flex justify-content-between w-100">
<TextField
id="reassigned-serial-no-input"
disabled={!updateReassigned}
className="w-100"
value={studentData.reassigned_serial_no}
placeholder={`Please enter the SNo.${studentData?.rownumber} Answer Booklet No`}
autoComplete="off"
onChange={(e) => {
setReassignedSno(e.target.value);
}}
/>
<Button
onClick={() => {
setUpdateReassigned(!updateReassigned);
}}
>
<EditButton />
</Button>
</Box>
</Box>
<Box className="py-2 d-flex justify-content-start">
<Box className="py-2 d-flex justify-content-start flex-column gap-2">
<Button
className="text-light bg-primary p-3"
disabled={!updateReassigned}
className="text-light bg-primary p-3 w-100"
disabled={!reasssingedSno}
onClick={updateReassignedSno}
>
Update
</Button>
<Button
className="text-light bg-primary p-3 w-100"
onClick={markAsAssigned}
>
Mark As Assigned
</Button>
</Box>
</Box>
</Box>
</>
)}
</Box>
<Box className="w-75 d-none d-md-block">
{dataFetched && studentData && (
<img
src={`https://docs.exampaper.vidh.ai/${studentData.s3_path}`}
width="60%"
height="auto"
/>
<Box
className="w-75 d-none d-md-block"
style={{ height: "800px", overflow: "auto" }}
>
{studentData && (
<>
<Box className="py-2">
<Button
className="bg-primary text-light p-3 mx-1"
onClick={ZoomInImage}
>
ZoomIn
</Button>
<Button
className="bg-primary text-light p-3 mx-1"
onClick={ZoomOutImage}
>
ZoomOut
</Button>
<Button
className="bg-primary text-light p-3 mx-1"
onClick={RotateImageLeft}
>
<RotateLeftIcon />
</Button>
<Button
className="bg-primary text-light p-3 mx-1"
onClick={RotateImageRight}
>
<RotateRightIcon />
</Button>
</Box>
<img
className="scanned-img"
src={`https://docs.exampaper.vidh.ai/${studentData?.s3_path}`}
width={`${scaleWidthValue}%`}
/>
</>
)}
</Box>
<Box className="w-md-75 d-block d-md-none">
{dataFetched && studentData && (
<img
src={`https://docs.exampaper.vidh.ai/${studentData.s3_path}`}
width="60%"
height="auto"
/>
<Box className="w-100 d-md-none overflow-auto">
{studentData && (
<>
<Box className="py-2">
<Button
className="bg-primary text-light p-3 mx-1"
onClick={ZoomInImage}
>
ZoomIn
</Button>
<Button
className="bg-primary text-light p-3 mx-1"
onClick={ZoomOutImage}
>
ZoomOut
</Button>
<Button
className="bg-primary text-light p-3 mx-1"
onClick={RotateImageLeft}
>
<RotateLeftIcon />
</Button>
<Button
className="bg-primary text-light p-3 mx-1"
onClick={RotateImageRight}
>
<RotateRightIcon />
</Button>
</Box>
<img
className="scanned-img"
src={`https://docs.exampaper.vidh.ai/${studentData.s3_path}`}
width={`${scaleWidthValue}%`}
/>
</>
)}
</Box>
</Box>

View File

@ -11,6 +11,7 @@ const BarcodeInput = ({setBookletInput,setDataFetched,bookletInput}) =>{
// }}
// noValidate
autoComplete="off"
className = "w-100"
>
<TextField id="outlined-basic" label="Barcode" variant="outlined" className='w-100' autoComplete="off" value={bookletInput} onChange={(e)=>{
setBookletInput(e.target.value)

View File

@ -1,23 +1,32 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import TextField from '@mui/material/TextField';
import * as React from "react";
import Box from "@mui/material/Box";
import TextField from "@mui/material/TextField";
const BookletInput = ({setBookletInput,setDataFetched,bookletInput}) =>{
return (
<Box
// component="form"
// sx={{
// '& > :not(style)': { m: 1, width: '25ch' },
// }}
// noValidate
autoComplete="off"
>
<TextField id="outlined-basic" label="Booklet Serial No" variant="outlined" className='w-100' autoComplete="off" value={bookletInput} onChange={(e)=>{
setBookletInput(e.target.value)
setDataFetched(false)
}}/>
</Box>
);
}
const BookletInput = ({ setBookletInput, setDataFetched, bookletInput }) => {
return (
<Box
// component="form"
// sx={{
// '& > :not(style)': { m: 1, width: '25ch' },
// }}
// noValidate
className="w-100"
autoComplete="off"
>
<TextField
id="outlined-basic"
label="Booklet Serial No"
variant="outlined"
className="w-100"
autoComplete="off"
value={bookletInput}
onChange={(e) => {
setBookletInput(e.target.value);
setDataFetched(false);
}}
/>
</Box>
);
};
export default BookletInput;
export default BookletInput;

View File

@ -1,23 +1,40 @@
import { Box } from "@mui/material";
import HomepageCard from "./HomepageCard";
import {useState,useEffect} from "react"
const Home = () => {
// const cards = [
// {
// title: "Reassingned Serial No Anomoly Manual Updation",
// url: "/anomoly/reassigned",
// },
// {
// title: "Part A OCR Anomoly Manual Updation",
// url: "/anomoly/partA",
// }
// ];
const cards = [
{
title: "Reassingned Serial No Anomoly Manual Updation",
url: "/anomoly/reassigned",
}]
},
// {
// title: "Part A OCR Anomoly - Batch 2022",
// url: "/anomoly/partA",
// },
{
title: "Part A OCR Anomoly Dummy",
url: "/anomoly/partA?type=new",
},
{
title: "Part A OCR Anomoly - Old Dummy",
url: "/anomoly/partA?type=old",
},
// {
// title:"Verification",
// url:"/verification"
// }
{
title:"Statistics",
url:"/statistics"
}
];
// const cards = [
// {
// title: "Reassingned Serial No Anomoly Manual Updation",
// url: "/anomoly/reassigned",
// }]
return (
<>
<Box>

View File

@ -1,17 +1,32 @@
import React from "react";
import React, { useEffect } from "react";
import { Box } from "@mui/material";
import Spinner from "react-bootstrap/Spinner";
const LoadingContainer = ({ loadingText }) => {
const LoadingContainerStyle = {
backgroundColor: "rgba(0,0,0,0.5)",
overflow: "auto",
overflow: "hidden",
position: "fixed",
top: 0,
left: 0,
width: "100vw",
height: "100vh",
zIndex: 1000, // Ensure it appears above other content
};
useEffect(() => {
const body = document.querySelector("body");
body.scrollTop = 0;
body.style.overflow = "hidden";
return () => {
body.style.overflow = "auto";
};
}, []);
return (
<>
<Box
className="d-flex justify-content-center position-absolute w-100 h-100 align-items-center"
className="d-flex justify-content-center align-items-center"
style={LoadingContainerStyle}
>
<Spinner animation="border" variant="light" role="status">

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,16 @@ 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 { useSearchParams } from "react-router-dom";
import { updatePartAanomolyData } from "../redux/actions/actions";
import {
useSelector,
useDispatch,
ReactReduxContext,
batch,
} from "react-redux";
import useEnhancedEffect from "@mui/material/utils/useEnhancedEffect";
import SystemNumberDialog from "./SystemNumberDialog";
const { Header, Content, Footer, Sider } = Layout;
function getItem(label, key, icon, children) {
@ -32,17 +42,6 @@ function getItem(label, key, icon, children) {
label,
};
}
// const items = [
// getItem('Option 1', '1', <PieChartOutlined />),
// getItem('Option 2', '2', <DesktopOutlined />),
// getItem('User', 'sub1', <UserOutlined />, [
// getItem('Tom', '3'),
// getItem('Bill', '4'),
// getItem('Alex', '5'),
// ]),
// getItem('Team', 'sub2', <TeamOutlined />, [getItem('Team 1', '6'), getItem('Team 2', '8')]),
// getItem('Files', '9', <FileOutlined />),
// ];
const items = [getItem("Reassigned Booklet No", "1", <PieChartOutlined />)];
@ -52,6 +51,68 @@ const PartAReassigned = () => {
const [tableRowData, setTableRowData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
let [searchParams, setSearchParams] = useSearchParams();
const [showSystemNoContainer, setShowSystemNoContainer] = useState(false);
const searchParamsType = searchParams.get("type");
const dispatch = useDispatch();
const reduxPartA2023AnomolyData = useSelector(
(state) => state?.partABatchAnomolyData
);
const reduxSystemNo = useSelector((state) => state?.systemNumber);
console.log("Redux partA 2023 anomoly data : ", reduxPartA2023AnomolyData);
useEffect(() => {
if (!reduxSystemNo) {
setShowSystemNoContainer(true);
} else {
let localstorageRecords;
// if (searchParamsType === "old") {
// localstorageRecords = localStorage.getItem("part-a-old-anomoly");
// if (localstorageRecords) {
// localstorageRecords = JSON.parse(localstorageRecords);
// }
// } else if (searchParamsType !== "old") {
// localstorageRecords = localStorage.getItem("part-a-anomoly");
// if (localstorageRecords) {
// localstorageRecords = JSON.parse(localstorageRecords);
// }
// }
fetchAnomalyData(reduxSystemNo)
// if (localstorageRecords && localstorageRecords.length > 0) {
// console.log(
// "Length of local storage records is high so aborting fetching ..."
// );
// console.log("The local storage records are ... ", localstorageRecords);
// setAnomolyData(localstorageRecords);
// dispatch(updatePartAanomolyData(localstorageRecords));
// const tmpData = [];
// for (const data of localstorageRecords) {
// tmpData.push(
// createData(
// data.s3_path,
// data.barcode,
// data.register_number,
// data.subject_code,
// data.type,
// reduxSystemNo
// )
// );
// }
// // console.log("Tmp data is : ", tmpData);
// if (tmpData.length > 0) {
// setTableRowData(tmpData);
// }
// } else {
// fetchAnomalyData(reduxSystemNo);
// }
// if(searchParamsType==="old"){
// const sytemData = localStorage.get("part-a-anomoly")
// }else if(searchParamsType !== "old"){
// const sytemData = localStorage.get("part-a-old-anomoly")
// }
}
}, [reduxSystemNo]);
useEffect(() => {
const handleResize = () => {
@ -75,17 +136,58 @@ const PartAReassigned = () => {
}, [windowWidth]);
const navigate = useNavigate();
function createData(barcode,register_number,subject_code,type) {
function createData(
s3_path,
barcode,
register_number,
subject_code,
type,
systemNo
) {
return {
barcode,register_number,subject_code,type
s3_path,
barcode,
register_number,
subject_code,
type,
systemNo,
};
}
const fetchAnomalyData = () => {
const updateSystemReservationStatus = async (systemRecords) => {
const payload = {
systemRecords,
sysNo:reduxSystemNo
};
try {
fetch(
`${
import.meta.env.VITE_REACT_APP_BACKEND_URL
}/updateSystemReservationStatus`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
}
)
.then((response) => response.json())
.then((responseData) => {
console.log("response from updation : ", responseData);
});
} catch (error) {
throw new Error("Error in update system records : ", systemRecords);
}
};
const fetchAnomalyData = (reduxSystemNo) => {
console.log("Fetching.......");
setIsLoading(true);
fetch(
`${import.meta.env.VITE_REACT_APP_BACKEND_URL}/fetchAnamolyPartAData`,
`${
import.meta.env.VITE_REACT_APP_BACKEND_URL
}/fetchAnamolyPartAData?type=${searchParamsType}&sysNo=${reduxSystemNo}`,
{
method: "GET",
headers: {
@ -101,12 +203,43 @@ const PartAReassigned = () => {
console.log("Response Data is : ", responseData);
setIsLoading(false);
if (responseData.status === "success") {
setAnomolyData(responseData.data);
const tmpData = [];
for (const data of responseData.data) {
tmpData.push(createData(data.barcode,data.register_number,data.subject_code,data.type));
console.log("System record ====== ",responseData.systemRecord)
var systemRecords = responseData?.data
if(!responseData.systemRecord){
systemRecords = getRecordsBySystemId(
responseData?.data,
reduxSystemNo
);
}
console.log("Tmp data is : ", tmpData);
updateSystemReservationStatus(systemRecords);
console.log("System records : ", systemRecords);
if (searchParamsType === "old") {
localStorage.setItem(
"part-a-old-anomoly",
JSON.stringify(systemRecords)
);
} else if (searchParamsType !== "old") {
localStorage.setItem(
"part-a-anomoly",
JSON.stringify(systemRecords)
);
}
setAnomolyData(systemRecords);
dispatch(updatePartAanomolyData(systemRecords));
const tmpData = [];
for (const data of systemRecords) {
tmpData.push(
createData(
data.s3_path,
data.barcode,
data.register_number,
data.subject_code,
data.type,
reduxSystemNo
)
);
}
// console.log("Tmp data is : ", tmpData);
if (tmpData.length > 0) {
setTableRowData(tmpData);
}
@ -118,9 +251,29 @@ const PartAReassigned = () => {
});
};
// useEffect(() => {
// fetchAnomalyData();
// }, []);
function getRecordsBySystemId(records, systemId) {
const new_data = [];
for (var i = 0; i < records.length; i++) {
var count = i % 5;
if (count === systemId - 1) {
new_data.push(records[i]);
}
}
return new_data;
}
const handleSystemNoChange = () => {
console.log("System No Change is called");
setShowSystemNoContainer(true);
};
useEffect(() => {
fetchAnomalyData();
}, []);
console.log("System no container show status : ", showSystemNoContainer);
}, [showSystemNoContainer]);
const {
token: { colorBgContainer, borderRadiusLG },
@ -171,14 +324,25 @@ const PartAReassigned = () => {
>
<QueryStatsIcon />
</Button> */}
<Button
className="bg-primary p-1 text-light"
onClick={() => {
navigate("/");
}}
>
<HomeIcon />
</Button>
<Box className="d-flex justify-content-between gap-md-4 gap-1 align-items-center">
{reduxSystemNo && (
<Box
className="h6 p-0 m-0 text-light bg-primary rounded h-100 d-flex align-items-center px-3"
style={{ cursor: "pointer" }}
onClick={handleSystemNoChange}
>
<b>System No : </b> {reduxSystemNo}
</Box>
)}
<Button
className="bg-primary p-1 text-light rounded h-100"
onClick={() => {
navigate("/");
}}
>
<HomeIcon />
</Button>
</Box>
</Box>
</Box>
</Header>
@ -191,10 +355,16 @@ const PartAReassigned = () => {
<Box className="w-100 d-flex justify-content-center">
{tableRowData.length > 0 && (
<TableComponent
batchType={searchParamsType}
rows={tableRowData}
type={"PartAReassigned"}
/>
)}
{tableRowData.length == 0 && (
<Box className="w-100 d-flex justify-content-center py-2 align-items-center text-center">
<h6>No Data Found !!</h6>
</Box>
)}
</Box>
</Box>
</Content>
@ -207,6 +377,12 @@ const PartAReassigned = () => {
</Footer>
</Layout>
{isLoading && <LoadingContainer loadingText={"Loading"} />}
{showSystemNoContainer && (
<SystemNumberDialog
setShowSystemNoContainer={setShowSystemNoContainer}
showSystemNoContainer={showSystemNoContainer}
/>
)}
</Layout>
);
};

View File

@ -0,0 +1,86 @@
import React, { useState,useEffect } from "react";
import Dialog from "@mui/material/Dialog";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle";
import { Button,Box } from "@mui/material";
import TextField from "@mui/material/TextField";
import { NavLink,Link } from "react-router-dom";
const SimpleDialog = ({dialogBoxConsent,setDialogBoxConsent,showDialogBox,setShowDialogBox,dialogText,batchType}) => {
const [open, setOpen] = useState(true); // Set open state to true by default
const [examCentreCode,setExamCentreCode] = useState(null)
const [examDate,setExamDate] = useState(null)
const [metaDataLink,setMetaDataLink] = useState(null)
const MetabaseLink = "http://metabase.usln.in/public/question/d8774923-09bb-4cd9-903b-559d417e12cf"
console.log("MetabaseLink : ",MetabaseLink)
console.log(import.meta.env)
const handleClose = () => {
setOpen(false);
};
const handleYes = () =>{
console.log("Consent is : ", dialogBoxConsent);
console.log("Dialog text before if condition :: ",dialogText)
console.log("showDialog Box : ",showDialogBox)
console.log("Setting Conset Yes")
setDialogBoxConsent("Yes")
setShowDialogBox(false)
}
const handleNo = () =>{
console.log("Consent is : ", dialogBoxConsent);
console.log("Dialog text before if condition :: ",dialogText)
console.log("showDialog Box : ",showDialogBox)
console.log("Setting consent NO")
setDialogBoxConsent("No")
setShowDialogBox(false)
}
useEffect(()=>{
if(examCentreCode && examDate){
setMetaDataLink(`http://metabase.usln.in/public/question/d8774923-09bb-4cd9-903b-559d417e12cf?internal_exam_centre_code=${examCentreCode}&ref_exam_date=${examDate}`)
}
},[examDate,examCentreCode])
return (
<Dialog open={open} onClose={handleClose}>
<DialogTitle>Error :</DialogTitle>
<DialogContent>
<DialogContentText>
<h6>Missing Data - {dialogText}</h6>
Data Entered Is Not found in the DB.Do you want to Continue editing ??
{batchType == "new" && <Box className="d-flex gap-4 my-4">
{/* <Link to={MetabaseLink} target="_blank">{MetabaseLink}</Link> */}
{/* <TextField
value={examCentreCode}
onChange={(e)=>{
setExamCentreCode(e.target.value)
}}
label={"Exam Centre Code"}
autoComplete="off"
/>
<TextField
value={examDate}
onChange={(e)=>{
setExamDate(e.target.value)
}}
label={"Exam Date"}
autoComplete="off"
/> */}
</Box>}
{/* {
metaDataLink && <iframe width="1000px" height="800px" src={metaDataLink}/>
} */}
<Box className="d-flex justify-content-end gap-2 my-3">
<Button className="bg-primary p-2 text-light" onClick={handleYes}>YES</Button>
<Button className="bg-primary p-2 text-light" onClick={handleNo}>NO</Button>
</Box>
</DialogContentText>
</DialogContent>
</Dialog>
);
}
export default SimpleDialog;

View File

@ -0,0 +1,410 @@
import React, { useState, useRef } from "react";
import {
DesktopOutlined,
FileOutlined,
PieChartOutlined,
TeamOutlined,
UserOutlined,
} from "@ant-design/icons";
import {
Breadcrumb,
Layout,
Menu,
Typography,
theme,
Select,
DatePicker,
} from "antd";
import { Box, Button } from "@mui/material";
import { useEffect } from "react";
import TextField from "@mui/material/TextField";
import EditButton from "./EditButton";
import { width } from "@mui/system";
import { ToastContainer, toast } from "react-toastify";
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";
import { Height } from "@mui/icons-material";
import StatsCard from "./StatsCard";
import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward";
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
const { Header, Content, Footer, Sider } = Layout;
function getItem(label, key, icon, children) {
return {
key,
icon,
children,
label,
};
}
const Statistics = () => {
const navigate = useNavigate();
const [part, setPart] = useState(null);
const [collapsed, setCollapsed] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [examCentreCode, setExamCentreCode] = useState(null);
const [isManualVerificationNeeded, setIsManualVerificationNeeded] =
useState(false);
const [recordsData, setRecordsData] = useState([]);
const [isCoverPage, setIsCoverPage] = useState(false);
const [isBackPage, setIsBackPage] = useState(false);
const [totalPages, setTotalPages] = useState(0);
const [startDate,setStartDate] = useState(null);
const [endDate,setEndDate] = useState(null);
const [pageNumber, setPageNumber] = useState(1);
const [currentPageRecords, setCurrentPageRecords] = useState(0);
const [distinctExamCentreCodes, setDistinctExamCentreCodes] = useState([]);
const items = [getItem("Reassigned Booklet No", "1", <PieChartOutlined />)];
const {
token: { colorBgContainer, borderRadiusLG },
} = theme.useToken();
const recordsPerPage = 5;
const fetchDistinctInternalExamCentreCode = () => {
try {
fetch(
`${
import.meta.env.VITE_REACT_APP_BACKEND_URL
}/fetchDistinctExamCentreCodes`,
{
method: "GET",
}
)
.then((response) => response.json())
.then((responseData) => {
console.log("ResponseData :: ", responseData);
if (responseData?.status === "success") {
setDistinctExamCentreCodes(responseData?.results);
}
});
} catch (error) {
throw new Error(error);
}
};
useEffect(() => {
fetchDistinctInternalExamCentreCode();
}, []);
useEffect(() => {
console.log("Distinct exam centre codes : ", distinctExamCentreCodes);
}, [distinctExamCentreCodes]);
const handleBackpageChange = (e) => {
if (e === "yes") {
setIsBackPage(1);
} else {
setIsBackPage(0);
}
};
const handleManualVerificatonChange = (e) => {
if (e === "yes") {
setIsManualVerificationNeeded(1);
} else {
setIsManualVerificationNeeded(0);
}
};
const handleCoverChange = (e) => {
console.log("Cover change : ", e);
if (e === "yes") {
setIsCoverPage(1);
} else {
setIsCoverPage(0);
}
};
const submitStatistics = async () => {
setIsLoading(true);
const payload = {
examCentreCode,
isBackPage,
isCoverPage,
isManualVerificationNeeded,
part,
startDate,
endDate
};
try {
const responseData = await fetch(
`${import.meta.env.VITE_REACT_APP_BACKEND_URL}/fetchStatsData`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
}
);
setIsLoading(false);
const response = await responseData.json();
console.log("Response data in fetchStatsdata : ", response);
if (response?.status === "success") {
setRecordsData(response?.results);
if (response.results !== 0) {
setTotalPages(Math.ceil(response?.results.length / recordsPerPage));
const startIndex = (pageNumber - 1) * recordsPerPage;
const endIndex = startIndex + recordsPerPage;
const newRecords = response.results.splice(startIndex, endIndex);
setCurrentPageRecords(newRecords);
}
}
} catch (err) {
throw new Error(err);
}
};
useEffect(() => {
console.log("Record Data in useeffeect : ", recordsData);
}, [recordsData]);
useEffect(() => {
console.log("Page number : ", pageNumber);
const startIndex = (pageNumber - 1) * recordsPerPage;
console.log("Start Index :: ", startIndex);
const endIndex = startIndex + recordsPerPage;
console.log("End index : ", endIndex);
const newPageRecords = recordsData.slice(startIndex, endIndex);
console.log("recordsData : ", recordsData);
console.log("New records : ", newPageRecords);
setCurrentPageRecords(newPageRecords);
const body = document.querySelector("body");
window.scrollTo(0, 0);
}, [pageNumber]);
return (
<div>
<Layout
style={{
minHeight: "100vh",
}}
>
<ToastContainer />
<Sider
collapsible
collapsed={collapsed}
onCollapse={(value) => setCollapsed(value)}
>
<div className="demo-logo-vertical" />
<Menu
theme="dark"
defaultSelectedKeys={["1"]}
mode="inline"
items={items}
/>
</Sider>
<Layout>
<Header
style={{
padding: 0,
background: colorBgContainer,
}}
>
<div 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>
<div className="d-flex justify-content-between gap-2">
<div 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>
</div>
</div>
</div>
</Header>
<Content
style={{
margin: "16px 16px",
}}
>
{/* Add the dropdowns and select buttons here */}
<div className="d-flex flex-wrap gap-4 align-items-center">
<div
className="dropdown-item mx-2"
style={{ width: "fit-content" }}
>
<label>Exam Centre Code:</label>
<Select
placeholder="Select Exam Centre Code"
style={{ width: 200 }}
onChange={(e) => {
console.log("Exam centre code : ", e);
setExamCentreCode(e);
}}
>
{distinctExamCentreCodes.length > 0 &&
distinctExamCentreCodes.map((code) => (
<Option value={code?.internal_exam_centre_code}>
{code?.internal_exam_centre_code}
</Option>
))}
</Select>
</div>
<div
className="dropdown-item mx-2"
style={{ width: "fit-content" }}
>
<label>Manual Verification Needed:</label>
<Select
placeholder="Select Verification Status"
style={{ width: 200 }}
onChange={handleManualVerificatonChange}
>
<Option value="yes">Yes</Option>
<Option value="no">No</Option>
</Select>
</div>
<div
className="dropdown-item mx-2"
style={{ width: "fit-content" }}
>
<label>Is Cover:</label>
<Select
placeholder="Select Cover Status"
style={{ width: 200 }}
onChange={handleCoverChange}
>
<Option value="yes">Yes</Option>
<Option value="no">No</Option>
</Select>
</div>
<div
className="dropdown-item mx-2"
style={{ width: "fit-content" }}
>
<label>Is Backpage:</label>
<Select
placeholder="Select Backpage Status"
style={{ width: 200 }}
onChange={handleBackpageChange}
>
<Option value="yes">Yes</Option>
<Option value="no">No</Option>
</Select>
</div>
<div
className="dropdown-item mx-2"
style={{ width: "fit-content" }}
>
<label>Part:</label>
<Select
placeholder="Select Part"
style={{ width: 200 }}
onChange={(e) => {
setPart(e);
}}
>
<Option value="partA">Part-A</Option>
<Option value="partC">Part-C</Option>
</Select>
</div>
<div
className="dropdown-item mx-2"
style={{ width: "fit-content" }}
>
<label>Date Range:</label>
<DatePicker.RangePicker onChange={(e)=>{
console.log("E ==== ",e)
if(e.length == 2){
setStartDate(`${e[0].$y}-${e[0].$M}-${e[0].$D}`)
setEndDate(`${e[1].$y}-${e[1].$M}-${e[1].$D}`)
}
}}/>
</div>
<div className="dropdown-item" style={{ width: "fit-content" }}>
<Button
class="btn bg-primary text-light px-5 rounded"
onClick={submitStatistics}
>
Submit
</Button>
</div>
</div>
<div>
{currentPageRecords.length > 0 &&
currentPageRecords.map((data, index) => (
<StatsCard
data={data}
records={currentPageRecords}
part={part}
/>
))}
</div>
{recordsData.length > 0 && (
<div>
<Button
class="btn btn-primary p-2 mx-2"
onClick={() => {
if (pageNumber > 1) {
setPageNumber((prev) => prev - 1);
}
}}
>
Previous
</Button>
{pageNumber}/{totalPages}
<Button
class="btn btn-primary p-2 mx-2"
onClick={() => {
if (pageNumber >= 0) {
setPageNumber((prev) => prev + 1);
}
}}
>
Next
</Button>
</div>
)}
<Box style={{ bottom: "10px", right: "10px", position: "fixed" }}>
<Button className="bg-primary text-light rounded" onClick={()=>{
console.log("Going down ..")
const body = document.body
window.scrollTo(0,body.scrollHeight)
}}>
<ArrowDownwardIcon />
</Button>
</Box>
</Content>
<Footer
style={{
textAlign: "center",
}}
>
exampaper.vidh.ai ©{new Date().getFullYear()}
</Footer>
</Layout>
{isLoading && <LoadingContainer loadingText={"Loading"} />}
</Layout>
</div>
);
};
export default Statistics;

View File

@ -0,0 +1,80 @@
import { Box } from "@mui/material";
const StatsCard = ({ records, data, part }) => {
console.log("Records : ", records);
// console.log("data ================ : ", data);
const keys = Object.keys(data);
// console.log("Part : ", part);
// // const Values = Object.Values(data)
// console.log("values ====== ", Object.values(data));
const values = Object.values(data);
// console.log("keys : ", keys);
const PartCKeysToCapture = [
"barcode",
"exam_centre_code",
"booklet_serial_no",
"subject_code",
"marks",
"manual_verification_needed",
"error",
"error_reason",
"error"
];
const PartAKeysToCapture = [
"barcode",
"exam_centre_code",
"booklet_serial_no",
"subject_code",
"manual_verification_needed",
"error",
"error_reason",
"error",
"type",
];
return (
<>
<Box class="d-flex flex-md-row flex-column justify-content-center align-items-center gap-2 my-5 border border-dark rounded">
<Box class="text-left d-flex flex-column justify-content-center mx-3">
{part === "partC" && (
<>
<Box class="my-3">
<h6>
<u>
<b>Record Data:</b>
</u>
</h6>
</Box>
{PartCKeysToCapture.map((key, index) => (
<h6 key={index}>
<b>{key}</b>: {data[key]}
</h6>
))}
</>
)}
{part === "partA" && (
<>
{PartAKeysToCapture.map((key, index) => (
<h6>
<b>{key}</b> : {data[key]}
{/* <h3>{key}</h3>
<h3>{index}</h3> */}
</h6>
))}
</>
)}
</Box>
<Box style={{width:"fit-content"}}>
<img
src={`https://docs.exampaper.vidh.ai/${data?.s3_path}`}
width="90%"
height="auto"
/>
</Box>
</Box>
</>
);
};
export default StatsCard;

View File

@ -0,0 +1,80 @@
import React, { useState, useEffect } from "react";
import Dialog from "@mui/material/Dialog";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle";
import { Button, Box } from "@mui/material";
import TextField from "@mui/material/TextField";
import { NavLink, Link, useNavigate } from "react-router-dom";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select from "@mui/material/Select";
import { useDispatch,useSelector } from "react-redux";
import { updateSystemNo } from "../redux/actions/actions";
const SystemNumberDialog = (setShowSystemNoContainer,showSystemNoContainer) => {
const dispatch = useDispatch();
const navigate = useNavigate()
const [open, setOpen] = useState(true); // Set open state to true by default
const reduxSystemNo = useSelector((state)=>state?.systemNumber)
console.log("Redux system No : ",reduxSystemNo)
const [systemNo, setSystemNo] = useState(1);
const handleClose = () => {
setOpen(false);
};
const handleSubmit = () => {
console.log("Handling submit")
dispatch(updateSystemNo(systemNo));
navigate("/")
handleClose(true)
};
useEffect(()=>{
console.log("System No in useEffect : ",systemNo)
},[systemNo])
const numberOfSystems = 5;
const selectValues = [];
for (var i = 1; i <= numberOfSystems; i++) {
selectValues.push({ value: Number(i), systemLabel: `System ${i}` });
}
return (
<Dialog open={open} onClose={handleClose}>
<DialogTitle>Choose Your System Number:</DialogTitle>
<DialogContent>
<DialogContentText>
<Select
labelId="system-no-select-label"
id="system-no-select"
className="w-100"
label="System No"
value={systemNo}
onChange={(e) => {
setSystemNo(e.target.value);
}}
>
{selectValues.length > 0 &&
selectValues.map((value) => (
<MenuItem value={value.value}>{value.systemLabel}</MenuItem>
))}
</Select>
<Box className="d-flex justify-content-end gap-2 my-3">
<Button
className="bg-primary p-2 text-light"
onClick={handleSubmit}
>
Submit
</Button>
</Box>
</DialogContentText>
</DialogContent>
</Dialog>
);
};
export default SystemNumberDialog;

View File

@ -4,10 +4,25 @@ import {
TablePagination,
tablePaginationClasses as classes,
} from "@mui/base/TablePagination";
import { Link } from "react-router-dom";
import TextField from "@mui/material/TextField";
import { Box } from "@mui/material";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select from "@mui/material/Select";
export default function TableComponent({ rows, type }) {
export default function TableComponent({
filterSelectedExamCentreCode,
setFilterSelectedExamCentreCode,
rows,
type,
distinctExamCentreCodes,
batchType
}) {
// console.log("Exam centre code in table component : ",distinctExamCentreCodes)
console.log("Rows in table component : ", rows);
console.log("Type is : ", type);
// console.log("Type is : ", type);
const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(5);
@ -24,11 +39,33 @@ export default function TableComponent({ rows, type }) {
setPage(0);
};
const handleFilterExamCentreCode = (e) => {
const ExamCentreCode = e.target.value;
setFilterSelectedExamCentreCode(ExamCentreCode);
};
return (
<Root className="overflow-auto" sx={{ maxWidth: "100%", width: 1200 }}>
{type === "AnomolyReassigned" && (
<>
<h5 className="py-2">Manual Verification Needed Students :</h5>
{/* <Box className="py-2">
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">Exam Centre Code</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
label="Exam Centre Code"
onChange={handleFilterExamCentreCode}
>
{distinctExamCentreCodes.length > 0 && (
distinctExamCentreCodes.map((exam_centre_code)=>(
<MenuItem key={exam_centre_code} value={exam_centre_code}>{exam_centre_code}</MenuItem>
))
)}
</Select>
</FormControl>
</Box> */}
<table aria-label="custom pagination table">
<thead>
<tr>
@ -52,11 +89,11 @@ export default function TableComponent({ rows, type }) {
<tr key={row.attendence_serial_no}>
<td>{row.attendence_serial_no}</td>
<td style={{ width: 160 }} align="right">
<a
href={`/anomoly/reassigned/booklet?sno=${row.student_slno}`}
<Link
to={`/anomoly/reassigned/booklet?sno=${row.student_slno}`}
>
{row.student_slno}
</a>
</Link>
</td>
<td style={{ width: 160 }} align="right">
{row.exam_centre_code}
@ -248,6 +285,7 @@ export default function TableComponent({ rows, type }) {
<table aria-label="custom pagination table">
<thead>
<tr>
<th>s3_path</th>
<th>Barcode</th>
<th>Subject Code</th>
<th>Register Number</th>
@ -263,8 +301,13 @@ export default function TableComponent({ rows, type }) {
: rows
).map((row) => (
<tr key={row.exam_centre_code}>
<td style={{ width: 160 }} align="right">
<Link to={`/anomoly/partA/booklet?batchType=${batchType}&barcode=${row.barcode}&s3Path=${row.s3_path}&sysNo=${row.systemNo}`}>
{row?.s3_path}
</Link>
</td>
<td style={{ width: 160 }} align="right">
<a href={`/anomoly/partA/booklet?barcode=${row.barcode}`}>{row.barcode}</a>
{row.barcode}
</td>
<td style={{ width: 160 }} align="right">
{row.subject_code}

View File

@ -0,0 +1,95 @@
import React, { useState, useEffect } from "react";
import Dialog from "@mui/material/Dialog";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle";
import { Button, Box } from "@mui/material";
import TextField from "@mui/material/TextField";
import { NavLink, Link } from "react-router-dom";
const ValidationContainer = ({
showValidationContainer,
setShowValidationContainer,
validateContainerData,
s3Path,
updatePartAanomoly
}) => {
const [open, setOpen] = useState(true); // Set open state to true by default
console.log("Validate Container Data : ", validateContainerData);
// const [examCentreCode,setExamCentreCode] = useState(null)
// const [examDate,setExamDate] = useState(null)
// const [metaDataLink,setMetaDataLink] = useState(null)
// const MetabaseLink = "http://metabase.usln.in/public/question/d8774923-09bb-4cd9-903b-559d417e12cf"
// console.log("MetabaseLink : ",MetabaseLink)
// console.log(import.meta.env)
const handleClose = () => {
setOpen(false);
};
return (
<Dialog open={open} onClose={handleClose}>
<DialogTitle>
<u>Students Data's :</u>
</DialogTitle>
<DialogContent>
<DialogContentText>
{validateContainerData.length > 0 ? (
<>
<Box className="d-flex">
<Box className="p-3">
<h6>
<strong>Student Name : </strong>
{validateContainerData[0]?.candidate_name}
</h6>
<h6>
<strong>Register Number : </strong>
{validateContainerData[0]?.register_number}
</h6>
<h6>
<strong>Subject Code : </strong>
{validateContainerData[0]?.subject_code}
</h6>
<h6>
<strong>Exam Centre Code : </strong>
{validateContainerData[0]?.exam_centre_code}
</h6>
<h6>
<strong>Exam Date : </strong>
{validateContainerData[0]?.exam_date}
</h6>
</Box>
{/* <Box>
<img src = {`https://docs.exampaper.vidh.ai/${s3Path}`}/>
</Box> */}
</Box>
</>
) : (
<Box className="p-3">
<h6>No student Record Found !!</h6>
</Box>
)}
<Box className="d-flex justify-content-between gap-2 my-3">
<Button
className="bg-primary p-2 text-light"
disabled={validateContainerData.length === 0}
onClick={()=>{
setShowValidationContainer(false)
updatePartAanomoly()
}}
>
Submit
</Button>
<Button
className="bg-primary p-2 text-light"
onClick={() => setShowValidationContainer(false)}
>
Close
</Button>
</Box>
</DialogContentText>
</DialogContent>
</Dialog>
);
};
export default ValidationContainer;

View File

@ -0,0 +1,335 @@
import React, { useState } from "react";
import {
DesktopOutlined,
FileOutlined,
PieChartOutlined,
TeamOutlined,
UserOutlined,
} from "@ant-design/icons";
import { Breadcrumb, Layout, Menu, Typography, theme } from "antd";
import BookletInput from "./BookletInput";
import { Box, Button } from "@mui/material";
import { useEffect } from "react";
import TextField from "@mui/material/TextField";
import EditButton from "./EditButton";
import { width } from "@mui/system";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { TablePagination } from "@mui/base/TablePagination";
import TableComponent from "./TableComponent";
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 { useSearchParams } from "react-router-dom";
import { updatePartAanomolyData } from "../redux/actions/actions";
import { useSelector, useDispatch, ReactReduxContext } from "react-redux";
import useEnhancedEffect from "@mui/material/utils/useEnhancedEffect";
import SystemNumberDialog from "./SystemNumberDialog";
const { Header, Content, Footer, Sider } = Layout;
function getItem(label, key, icon, children) {
return {
key,
icon,
children,
label,
};
}
const items = [getItem("Reassigned Booklet No", "1", <PieChartOutlined />)];
const Verification = () => {
const [collapsed, setCollapsed] = useState(false);
const [anomolyData, setAnomolyData] = useState([]);
const [tableRowData, setTableRowData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
let [searchParams, setSearchParams] = useSearchParams();
const [showSystemNoContainer, setShowSystemNoContainer] = useState(false);
const searchParamsType = searchParams.get("type");
const dispatch = useDispatch();
const reduxPartA2023AnomolyData = useSelector(
(state) => state?.partABatchAnomolyData
);
const reduxSystemNo = useSelector((state) => state?.systemNumber);
console.log("Redux partA 2023 anomoly data : ", reduxPartA2023AnomolyData);
useEffect(() => {
if (!reduxSystemNo) {
setShowSystemNoContainer(true);
} else {
fetchAnomalyData(reduxSystemNo);
// if(searchParamsType==="old"){
// const sytemData = localStorage.get("part-a-anomoly")
// }else if(searchParamsType !== "old"){
// const sytemData = localStorage.get("part-a-old-anomoly")
// }
}
}, [reduxSystemNo]);
useEffect(() => {
const handleResize = () => {
setWindowWidth(window.innerWidth);
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
useEffect(() => {
if (windowWidth < 800) {
setCollapsed(true);
}
if (windowWidth > 800) {
setCollapsed(false);
}
}, [windowWidth]);
const navigate = useNavigate();
function createData(
s3_path,
barcode,
register_number,
subject_code,
type,
systemNo
) {
return {
s3_path,
barcode,
register_number,
subject_code,
type,
systemNo,
};
}
const updateSystemReservationStatus = async (systemRecords) => {
const payload={
systemRecords,
}
try {
fetch(`${import.meta.env.VITE_REACT_APP_BACKEND_URL}/updateSystemReservationStatus`,{
method:"POST",
headers:{
"Content-Type":"application/json"
},
body:JSON.stringify(payload)
}).then(response=>response.json()).then(responseData=>{
console.log("response from updation : ",responseData)
})
} catch (error) {
throw new Error("Error in update system records : ",systemRecords)
}
};
const fetchAnomalyData = (reduxSystemNo) => {
console.log("Fetching.......");
setIsLoading(true);
fetch(
`${
import.meta.env.VITE_REACT_APP_BACKEND_URL
}/fetchAnamolyPartAData?type=${searchParamsType}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
)
.then((response) => {
console.log("Response fetched..");
return response.json();
})
.then((responseData) => {
console.log("Response Data is : ", responseData);
setIsLoading(false);
if (responseData.status === "success") {
const systemRecords = getRecordsBySystemId(
responseData?.data,
reduxSystemNo
);
updateSystemReservationStatus(systemRecords)
console.log("System records : ", systemRecords);
if (searchParamsType === "old") {
localStorage.setItem(
"part-a-old-anomoly",
JSON.stringify(systemRecords)
);
} else if (searchParamsType !== "old") {
localStorage.setItem(
"part-a-anomoly",
JSON.stringify(systemRecords)
);
}
setAnomolyData(systemRecords);
dispatch(updatePartAanomolyData(systemRecords));
const tmpData = [];
for (const data of systemRecords) {
tmpData.push(
createData(
data.s3_path,
data.barcode,
data.register_number,
data.subject_code,
data.type,
reduxSystemNo
)
);
}
// console.log("Tmp data is : ", tmpData);
if (tmpData.length > 0) {
setTableRowData(tmpData);
}
}
})
.catch((error) => {
console.error("Error fetching data: ", error);
setIsLoading(false);
});
};
// useEffect(() => {
// fetchAnomalyData();
// }, []);
function getRecordsBySystemId(records, systemId) {
const new_data = [];
for (var i = 0; i < records.length; i++) {
var count = i % 5;
if (count === systemId - 1) {
new_data.push(records[i]);
}
}
return new_data;
}
const handleSystemNoChange = () => {
console.log("System No Change is called");
setShowSystemNoContainer(true);
};
useEffect(() => {
console.log("System no container show status : ", showSystemNoContainer);
}, [showSystemNoContainer]);
const {
token: { colorBgContainer, borderRadiusLG },
} = theme.useToken();
return (
<Layout
style={{
minHeight: "100vh",
}}
>
<ToastContainer />
<Sider
collapsible
collapsed={collapsed}
onCollapse={(value) => setCollapsed(value)}
>
<div className="demo-logo-vertical" />
<Menu
theme="dark"
defaultSelectedKeys={["1"]}
mode="inline"
items={items}
/>
</Sider>
<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">
{reduxSystemNo && (
<Box
className="h6 p-0 m-0 text-light bg-primary rounded h-100 d-flex align-items-center px-3"
style={{ cursor: "pointer" }}
onClick={handleSystemNoChange}
>
<b>System No : </b> {reduxSystemNo}
</Box>
)}
<Button
className="bg-primary p-1 text-light rounded h-100"
onClick={() => {
navigate("/");
}}
>
<HomeIcon />
</Button>
</Box>
</Box>
</Box>
</Header>
<Content
style={{
margin: "16px 16px",
}}
>
<Box className="w-100 d-flex justify-content-between">
<Box className="w-100 d-flex justify-content-center">
{tableRowData.length > 0 && (
<TableComponent
batchType={searchParamsType}
rows={tableRowData}
type={"PartAReassigned"}
/>
)}
{tableRowData.length == 0 && (
<Box className="w-100 d-flex justify-content-center py-2 align-items-center text-center">
<h6>No Data Found !!</h6>
</Box>
)}
</Box>
</Box>
</Content>
<Footer
style={{
textAlign: "center",
}}
>
exampaper.vidh.ai ©{new Date().getFullYear()}
</Footer>
</Layout>
{isLoading && <LoadingContainer loadingText={"Loading"} />}
{showSystemNoContainer && (
<SystemNumberDialog
setShowSystemNoContainer={setShowSystemNoContainer}
showSystemNoContainer={showSystemNoContainer}
/>
)}
</Layout>
);
};
export default Verification;

View File

@ -1,12 +1,15 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import 'bootstrap/dist/css/bootstrap.min.css';
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import "bootstrap/dist/css/bootstrap.min.css";
import { Provider } from "react-redux";
import store from "./redux/store/store";
ReactDOM.createRoot(document.getElementById('root')).render(
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);

View File

@ -0,0 +1,14 @@
export const updateAttendenceAnomolyData = (data) =>({
type:"UPDATE_ATTENDENCE_ANOMOLY_DATA",
payload:data,
})
export const updatePartAanomolyData = (data) =>({
type:"UPDATE_PART-A_ANOMOLY_DATA",
payload:data
})
export const updateSystemNo = (data) => ({
type:"UPDATE_SYSTEM_NO",
payload:data
})

View File

@ -0,0 +1,22 @@
const initialState = {
attendenceAnomolyData : [],
partABatchAnomolyData : [],
systemNumber : null
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'UPDATE_ATTENDENCE_ANOMOLY_DATA':
return { ...state, attendenceAnomolyData:action?.payload};
case 'UPDATE_PART-A_ANOMOLY_DATA':
return { ...state, partABatchAnomolyData:action?.payload};
case 'UPDATE_SYSTEM_NO':
return { ...state,systemNumber:action?.payload}
default:
return state;
}
};
export default reducer;

View File

@ -0,0 +1,7 @@
// store.js
import { createStore } from 'redux';
import reducer from '../reducers/Reducer'; // Import your reducer
const store = createStore(reducer); // Create store with single reducer
export default store;