attendence additional sheet ui changes done v1
This commit is contained in:
parent
33147c8b0e
commit
5e091b9a53
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"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
filename*,enter filename,"INSTUCTIONS: Present means mark '0', Absent means mark '1', Assigned means mark as 0, Reassigned means mark '1'. NOTE: all '*' fields are mandatory so please all '*' compulsory. Get filename from the UI which is as Imagename",,,
|
||||
,,,,,
|
||||
subject_code*,enter subject_code,,,,
|
||||
exam_centre_code*,enter exam_centre_code,,,,
|
||||
subject_title*,enter subject_title,,,,
|
||||
degree_with_branch*,enter degree_with_branch,,,,
|
||||
exam_date*,enter exam_date,,,,
|
||||
exam_date_session,enter exam_date_session,,,,
|
||||
cover_a,enter cover_a,,,,
|
||||
cover_b,enter cover_b,,,,
|
||||
,,,,,
|
||||
student_data,,,,,
|
||||
sno*,register_number*,Present/Absent*,Assigned/Reassigned*,reassigned_sno*,signed*
|
||||
1,,,,,
|
||||
|
File diff suppressed because it is too large
Load Diff
|
|
@ -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 AttendanceAdditionalSheet from "./Components/AttendanceAdditionalSheet";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
|
|
@ -26,6 +27,10 @@ function App() {
|
|||
path="/anomoly/attendence/reassigned"
|
||||
element={<AnomolyReassigned />}
|
||||
></Route>
|
||||
<Route
|
||||
path='/anomoly/attendence/additionalSheet'
|
||||
element={<AttendanceAdditionalSheet/>}
|
||||
></Route>
|
||||
<Route
|
||||
path="/anomoly/reassigned/booklet"
|
||||
element={<AttendenceCorrection />}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ import {useState,useEffect} from "react"
|
|||
const AnomolyAttendencePage = () =>{
|
||||
const cards = [
|
||||
{
|
||||
title: "Reassingned Serial No",
|
||||
title: "Reassigned Serial Number Updation",
|
||||
url: "/anomoly/attendence/reassigned"
|
||||
},
|
||||
{
|
||||
title: "Additional Record Insertion",
|
||||
title: "Additional Student Record Insertion",
|
||||
url: "/anomoly/attendence/additionalRecord",
|
||||
}, {
|
||||
title: "Additional Sheet Insertion",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,285 @@
|
|||
// 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 { updateAttendenceAnomolyData } from "../redux/actions/actions";
|
||||
// import { useDispatch, useSelector } from "react-redux";
|
||||
// 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 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("")
|
||||
// const [showSystemNoContainer, setShowSystemNoContainer] = useState(false);
|
||||
|
||||
// // Log Redux store state
|
||||
// console.log("Redux store state after dispatch:", reduxAnomolyData);
|
||||
// const reduxSystemNo = useSelector((state) => state?.systemNumber);
|
||||
// console.log("redux system no: ", reduxSystemNo)
|
||||
|
||||
// useEffect(()=>{
|
||||
// if(!reduxSystemNo){
|
||||
// setShowSystemNoContainer(true);
|
||||
// }else{
|
||||
// fetchAnomalyData(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(
|
||||
// attendence_serial_no,
|
||||
// answer_booklet_sno,
|
||||
// exam_centre_code,
|
||||
// exam_centre,
|
||||
// student_name,
|
||||
// register_number,
|
||||
// reassigned_serial_no
|
||||
// ) {
|
||||
// return {
|
||||
// attendence_serial_no,
|
||||
// answer_booklet_sno,
|
||||
// exam_centre_code,
|
||||
// exam_centre,
|
||||
// student_name,
|
||||
// register_number,
|
||||
// reassigned_serial_no,
|
||||
// };
|
||||
// }
|
||||
|
||||
|
||||
// const fetchAnomalyData = (reduxSystemNo) => {
|
||||
// console.log("Fetching.......");
|
||||
// setIsLoading(true);
|
||||
// fetch(
|
||||
// `${
|
||||
// import.meta.env.VITE_REACT_APP_BACKEND_URL
|
||||
// }/fetchAnamolyAttendenceData?sysNo=${reduxSystemNo}`,
|
||||
// {
|
||||
// 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);
|
||||
// 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) => {
|
||||
// console.error("Error fetching data: ", error);
|
||||
// setIsLoading(false);
|
||||
// });
|
||||
// };
|
||||
|
||||
|
||||
// const handleSystemNoChange = () => {
|
||||
// console.log("System No Change is called");
|
||||
// setShowSystemNoContainer(true);
|
||||
// };
|
||||
|
||||
// useEffect(()=>{
|
||||
// console.log("redux sys no: ", reduxSystemNo)
|
||||
// },[])
|
||||
|
||||
// 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">
|
||||
// <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>
|
||||
// )}
|
||||
// </Box>
|
||||
// <Button
|
||||
// className="bg-primary p-1 text-light"
|
||||
// onClick={() => {
|
||||
// navigate("/anomoly/reassigned/stats");
|
||||
// }}
|
||||
// >
|
||||
// <QueryStatsIcon />
|
||||
// </Button>
|
||||
// <Button
|
||||
// className="bg-primary p-1 text-light"
|
||||
// onClick={() => {
|
||||
// navigate("/");
|
||||
// }}
|
||||
// >
|
||||
// <HomeIcon />
|
||||
// </Button>
|
||||
// </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
|
||||
// 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>
|
||||
// <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 AnomolyReassigned;
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Box, Button} from "@mui/material"
|
||||
import { ToastContainer } from "react-toastify";
|
||||
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
||||
import HomeIcon from "@mui/icons-material/Home";
|
||||
|
||||
import { Breadcrumb, Layout, Menu, Typography, theme } from "antd";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import TableComponent from "./TableComponent";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import TableComponentAdditionalSheet from "./TableComponentAdditionalSheet";
|
||||
const { Header, Content, Footer, Sider } = Layout;
|
||||
|
||||
function AttendanceAdditionalSheet() {
|
||||
const [tableRowData, setTableRowData] = useState([]);
|
||||
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const [anomolyData, setAnomolyData] = useState([]);
|
||||
const [filteredAnomolyData,setFilterAnomolyData] = useState([])
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [distinctExamCentreCodes,setDistinctExamCentreCodes] = useState([])
|
||||
const dispatch = useDispatch()
|
||||
const reduxAnomolyData = useSelector((state) => state.attendenceAnomolyData);
|
||||
const [filterSelectedExamCentreCode,setFilterSelectedExamCentreCode] = useState("")
|
||||
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]);
|
||||
|
||||
|
||||
function createData(
|
||||
image_name,
|
||||
s3_image_path
|
||||
) {
|
||||
return {
|
||||
image_name,
|
||||
s3_image_path
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
const tmpData = [];
|
||||
for (const data of anomolyData) {
|
||||
tmpData.push(
|
||||
createData(
|
||||
data.image_name,
|
||||
data.s3_image_path
|
||||
// data.attendence_serial_no,
|
||||
// data.answer_booklet_sno,
|
||||
// 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
|
||||
}/fetchAnamolyAttendenceAdditionalSheetData`,
|
||||
{
|
||||
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);
|
||||
// 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) => {
|
||||
console.error("Error fetching data: ", error);
|
||||
setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
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();
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
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("/");
|
||||
}}
|
||||
>
|
||||
<HomeIcon />
|
||||
</Button>
|
||||
</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
|
||||
filterSelectedExamCentreCode = {filterSelectedExamCentreCode}
|
||||
setFilterSelectedExamCentreCode = {setFilterSelectedExamCentreCode}
|
||||
rows={tableRowData}
|
||||
type={"AdditionalSheet"}
|
||||
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>
|
||||
|
||||
|
||||
</Layout>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export default AttendanceAdditionalSheet;
|
||||
|
|
@ -5,7 +5,7 @@ import {useState,useEffect} from "react"
|
|||
const Home = () => {
|
||||
const cards = [
|
||||
{
|
||||
title: "Reassingned Serial No Anomoly Manual Updation",
|
||||
title: "Reassigned Serial No Anomoly Manual Updation (ATTENDANCE)",
|
||||
url: "/anomoly/attendence",
|
||||
},
|
||||
// {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
import * as React from 'react';
|
||||
import Button from '@mui/material/Button';
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import AppBar from '@mui/material/AppBar';
|
||||
import Toolbar from '@mui/material/Toolbar';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import Slide from '@mui/material/Slide';
|
||||
import ZoomInIcon from '@mui/icons-material/ZoomIn';
|
||||
import ZoomOutIcon from '@mui/icons-material/ZoomOut';
|
||||
import RotateRightIcon from '@mui/icons-material/RotateRight';
|
||||
|
||||
const Transition = React.forwardRef(function Transition(props, ref) {
|
||||
return <Slide direction="up" ref={ref} {...props} />;
|
||||
});
|
||||
|
||||
export default function ImageDialog({ imagePath, setIsDialogOpen }) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
|
||||
const [scaleWidthValue, setScaleWidthValue] = React.useState(80);
|
||||
const [rotateValue, setRotateValue] = React.useState(0);
|
||||
|
||||
const handleClickOpen = () => {
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
setIsDialogOpen(false);
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
handleClickOpen();
|
||||
}, []);
|
||||
|
||||
|
||||
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)`;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Dialog
|
||||
fullScreen
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
TransitionComponent={Transition}
|
||||
>
|
||||
<AppBar sx={{ position: 'relative' }}>
|
||||
<Toolbar>
|
||||
<IconButton
|
||||
edge="start"
|
||||
color="inherit"
|
||||
onClick={handleClose}
|
||||
aria-label="close"
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={ZoomInImage}
|
||||
aria-label="zoom in"
|
||||
>
|
||||
<ZoomInIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={ZoomOutImage}
|
||||
aria-label="zoom out"
|
||||
>
|
||||
<ZoomOutIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={RotateImageLeft}
|
||||
aria-label="rotate"
|
||||
>
|
||||
<RotateRightIcon />
|
||||
</IconButton>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%', overflow:'auto' }}>
|
||||
<img
|
||||
className="scanned-img"
|
||||
style={{marginTop:'60%'}}
|
||||
width={`${scaleWidthValue}%`}
|
||||
src={`https://docs.exampaper.vidh.ai/${imagePath}`}
|
||||
alt="S3 Image"
|
||||
/>
|
||||
</div>
|
||||
</Dialog>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
|
@ -11,6 +11,12 @@ 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 Backdrop from '@mui/material/Backdrop';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import Snackbar from '@mui/material/Snackbar';
|
||||
import ImageDialog from "./ImageDialog";
|
||||
import { ToastContainer, toast } from "react-toastify";
|
||||
|
||||
|
||||
export default function TableComponent({
|
||||
filterSelectedExamCentreCode,
|
||||
|
|
@ -26,6 +32,33 @@ export default function TableComponent({
|
|||
const [page, setPage] = React.useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = React.useState(5);
|
||||
|
||||
const [isDialogOpen, setIsDialogOpen] = React.useState(false);
|
||||
const [currentImagePath, setCurrentImagePath] = React.useState('');
|
||||
|
||||
const [openLoader, setOpenLoader] = React.useState(false);
|
||||
const handleCloseLoader = () => {
|
||||
setOpenLoader(false);
|
||||
};
|
||||
const handleOpenLoader = () => {
|
||||
setOpenLoader(true);
|
||||
};
|
||||
|
||||
const [state, setState] = React.useState({
|
||||
open: false,
|
||||
vertical: 'top',
|
||||
horizontal: 'center',
|
||||
message: ''
|
||||
});
|
||||
const { vertical, horizontal, open, message } = state;
|
||||
|
||||
const handleClick = (newState) => () => {
|
||||
setState({ ...newState, open: true });
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setState({ ...state, open: false });
|
||||
};
|
||||
|
||||
// Avoid a layout jump when reaching the last page with empty rows.
|
||||
const emptyRows =
|
||||
page > 0 ? Math.max(0, (1 + page) * rowsPerPage - rows.length) : 0;
|
||||
|
|
@ -44,6 +77,66 @@ export default function TableComponent({
|
|||
setFilterSelectedExamCentreCode(ExamCentreCode);
|
||||
};
|
||||
|
||||
const handleImageClick = (imagePath) => {
|
||||
console.log("imagepath:",imagePath)
|
||||
setCurrentImagePath(imagePath);
|
||||
setIsDialogOpen(true)
|
||||
};
|
||||
|
||||
const handleCloseDialog = () => {
|
||||
setIsDialogOpen(false);
|
||||
setCurrentImagePath('');
|
||||
};
|
||||
|
||||
const [file, setFile] = React.useState(null);
|
||||
const [csvData, setCsvData] = React.useState([]);
|
||||
|
||||
const handleFileChange = (event) => {
|
||||
setFile(event.target.files[0]);
|
||||
console.log("event.target.files[0]: ",event.target.files[0])
|
||||
};
|
||||
|
||||
const handleFileUpload = async () => {
|
||||
if (!file) {
|
||||
alert('Please upload a CSV file first.');
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
try {
|
||||
handleOpenLoader()
|
||||
const response = await fetch(
|
||||
`${
|
||||
import.meta.env.VITE_REACT_APP_BACKEND_URL
|
||||
}/uploadAdditionalAttendanceCsv`,
|
||||
{
|
||||
method: "POST",
|
||||
body: formData
|
||||
}
|
||||
)
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('File uploaded successfully:', data);
|
||||
handleCloseLoader()
|
||||
toast.success(data.message);
|
||||
// handleClick({ vertical: 'top', horizontal: 'right', message:data.message })
|
||||
} else {
|
||||
console.error('File upload failed:', response.statusText);
|
||||
handleCloseLoader()
|
||||
toast.error("failed to upload");
|
||||
// handleClick({ vertical: 'top', horizontal: 'right', message:data.message })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error uploading file:', error);
|
||||
handleCloseLoader()
|
||||
toast.error("failed to upload");
|
||||
// handleClick({ vertical: 'top', horizontal: 'right', message:data.message })
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Root className="overflow-auto" sx={{ maxWidth: "100%", width: 1200 }}>
|
||||
{type === "AnomolyReassigned" && (
|
||||
|
|
@ -435,6 +528,138 @@ export default function TableComponent({
|
|||
</table>
|
||||
</>
|
||||
)}
|
||||
{type === "AdditionalSheet" && (
|
||||
<>
|
||||
<h5 className="py-2">Attendance Additional Sheet</h5>
|
||||
<div style={{ width: '200px', height: '50px', backgroundColor: 'lightblue', display: 'flex', justifyContent: 'center', alignItems: 'center', borderRadius: '5px' }}>
|
||||
<a
|
||||
style={{
|
||||
textDecoration: 'none',
|
||||
color: 'black',
|
||||
padding: '10px 20px',
|
||||
backgroundColor: 'white',
|
||||
border: '1px solid black',
|
||||
borderRadius: '5px',
|
||||
textAlign: 'center',
|
||||
display: 'inline-block'
|
||||
}}
|
||||
href={"/src/assets/additional_attendance_template.csv"}
|
||||
download={"additional_attendance_template.csv"}
|
||||
>
|
||||
Download Template CSV
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<p>Please download the CSV file and by verifying the image type appropriately</p>
|
||||
|
||||
<table aria-label="custom pagination table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Image Name</th>
|
||||
<th>upload csv</th>
|
||||
<th>Image</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(rowsPerPage > 0
|
||||
? rows.slice(
|
||||
page * rowsPerPage,
|
||||
page * rowsPerPage + rowsPerPage
|
||||
)
|
||||
: rows
|
||||
).map((row) => (
|
||||
<tr key={row.exam_centre_code}>
|
||||
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.image_name}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
<div>
|
||||
<input type="file" accept=".csv" onChange={handleFileChange} />
|
||||
<button style={{width:'130px', height:'30px', fontSize:'12px', textAlign:'center'}} onClick={handleFileUpload}>Upload CSV</button>
|
||||
|
||||
</div>
|
||||
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
<div>
|
||||
<span style={{cursor:'pointer', color:'blue'}} onClick={() => handleImageClick(row.s3_image_path)}>
|
||||
Preview Image
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>
|
||||
<a style={{textDecoration: 'none'}} href={`https://docs.exampaper.vidh.ai/${row.s3_image_path}`} download>
|
||||
Download Image
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
{/* <td style={{ width: 160 }} align="right">
|
||||
<Link
|
||||
to={`www.google.com`}
|
||||
>
|
||||
{row?.s3_image_path}
|
||||
</Link>
|
||||
</td> */}
|
||||
</tr>
|
||||
))}
|
||||
{emptyRows > 0 && (
|
||||
<tr style={{ height: 41 * emptyRows }}>
|
||||
<td colSpan={3} aria-hidden />
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<CustomTablePagination
|
||||
rowsPerPageOptions={[5, 10, 25, { label: "All", value: -1 }]}
|
||||
colSpan={3}
|
||||
count={rows.length}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
slotProps={{
|
||||
select: {
|
||||
"aria-label": "rows per page",
|
||||
},
|
||||
actions: {
|
||||
showFirstButton: true,
|
||||
showLastButton: true,
|
||||
},
|
||||
}}
|
||||
onPageChange={handleChangePage}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
/>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</>
|
||||
)}
|
||||
{
|
||||
isDialogOpen && (
|
||||
<ImageDialog
|
||||
imagePath={currentImagePath}
|
||||
setIsDialogOpen={setIsDialogOpen}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<Backdrop
|
||||
sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
||||
open={openLoader}
|
||||
>
|
||||
<CircularProgress color="inherit" />
|
||||
</Backdrop>
|
||||
|
||||
<Box sx={{ width: 500 }}>
|
||||
<Snackbar
|
||||
anchorOrigin={{ vertical, horizontal }}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
message={message}
|
||||
key={vertical + horizontal}
|
||||
/>
|
||||
</Box>
|
||||
<ToastContainer />
|
||||
</Root>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,702 @@
|
|||
import * as React from "react";
|
||||
import { styled } from "@mui/system";
|
||||
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";
|
||||
import Backdrop from '@mui/material/Backdrop';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import ImageDialog from "./ImageDialog";
|
||||
import { Button } from "bootstrap";
|
||||
|
||||
export default function TableComponentAdditionalSheet({
|
||||
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);
|
||||
const [page, setPage] = React.useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = React.useState(5);
|
||||
|
||||
const [isDialogOpen, setIsDialogOpen] = React.useState(false);
|
||||
const [currentImagePath, setCurrentImagePath] = React.useState('');
|
||||
|
||||
const [openLoader, setOpenLoader] = React.useState(false);
|
||||
const handleCloseLoader = () => {
|
||||
setOpenLoader(false);
|
||||
};
|
||||
const handleOpenLoader = () => {
|
||||
setOpenLoader(true);
|
||||
};
|
||||
|
||||
// Avoid a layout jump when reaching the last page with empty rows.
|
||||
const emptyRows =
|
||||
page > 0 ? Math.max(0, (1 + page) * rowsPerPage - rows.length) : 0;
|
||||
|
||||
const handleChangePage = (event, newPage) => {
|
||||
setPage(newPage);
|
||||
};
|
||||
|
||||
const handleChangeRowsPerPage = (event) => {
|
||||
setRowsPerPage(parseInt(event.target.value, 10));
|
||||
setPage(0);
|
||||
};
|
||||
|
||||
const handleFilterExamCentreCode = (e) => {
|
||||
const ExamCentreCode = e.target.value;
|
||||
setFilterSelectedExamCentreCode(ExamCentreCode);
|
||||
};
|
||||
|
||||
const handleImageClick = (imagePath) => {
|
||||
console.log("imagepath:",imagePath)
|
||||
setCurrentImagePath(imagePath);
|
||||
setIsDialogOpen(true)
|
||||
};
|
||||
|
||||
const handleCloseDialog = () => {
|
||||
setIsDialogOpen(false);
|
||||
setCurrentImagePath('');
|
||||
};
|
||||
|
||||
const [file, setFile] = React.useState(null);
|
||||
const [csvData, setCsvData] = React.useState([]);
|
||||
|
||||
const handleFileChange = (event) => {
|
||||
setFile(event.target.files[0]);
|
||||
console.log("event.target.files[0]: ",event.target.files[0])
|
||||
};
|
||||
|
||||
const handleFileUpload = async () => {
|
||||
if (!file) {
|
||||
alert('Please upload a CSV file first.');
|
||||
return;
|
||||
}
|
||||
handleOpenLoader()
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${
|
||||
import.meta.env.VITE_REACT_APP_BACKEND_URL
|
||||
}/uploadAdditionalAttendanceCsv`,
|
||||
{
|
||||
method: "POST",
|
||||
body: formData
|
||||
}
|
||||
)
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('File uploaded successfully:', data);
|
||||
handleCloseLoader()
|
||||
|
||||
} else {
|
||||
console.error('File upload failed:', response.statusText);
|
||||
handleCloseLoader()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error uploading file:', error);
|
||||
handleCloseLoader()
|
||||
}
|
||||
};
|
||||
|
||||
const parseCSV = (text) => {
|
||||
const rows = text.split('\n');
|
||||
const data = rows.map(row => row.split(','));
|
||||
setCsvData(data);
|
||||
};
|
||||
|
||||
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>
|
||||
|
||||
<th>Attendance Image</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(rowsPerPage > 0
|
||||
? rows.slice(
|
||||
page * rowsPerPage,
|
||||
page * rowsPerPage + rowsPerPage
|
||||
)
|
||||
: rows
|
||||
).map((row) => (
|
||||
<tr key={row.attendence_serial_no}>
|
||||
<td>{row.attendence_serial_no}</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{/* <Link
|
||||
to={`/anomoly/reassigned/booklet?sno=${row?.answer_booklet_sno}`}
|
||||
>
|
||||
{row.answer_booklet_sno}
|
||||
</Link> */}
|
||||
</td>
|
||||
{/* <td style={{ width: 160 }} align="right">
|
||||
{row.exam_centre_code}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.exam_centre}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.student_name}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.register_number}
|
||||
</td> */}
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.s3_path}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{emptyRows > 0 && (
|
||||
<tr style={{ height: 41 * emptyRows }}>
|
||||
<td colSpan={3} aria-hidden />
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<CustomTablePagination
|
||||
rowsPerPageOptions={[5, 10, 25, { label: "All", value: -1 }]}
|
||||
colSpan={3}
|
||||
count={rows.length}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
slotProps={{
|
||||
select: {
|
||||
"aria-label": "rows per page",
|
||||
},
|
||||
actions: {
|
||||
showFirstButton: true,
|
||||
showLastButton: true,
|
||||
},
|
||||
}}
|
||||
onPageChange={handleChangePage}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
/>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</>
|
||||
)}
|
||||
{type === "ReassignedStats" && (
|
||||
<>
|
||||
<h5 className="py-2">Exam Centre Code Complete MetaData :</h5>
|
||||
<table aria-label="custom pagination table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Exam Centre Code</th>
|
||||
<th>Total Scanned Count</th>
|
||||
<th>Manual Verification Count</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(rowsPerPage > 0
|
||||
? rows.slice(
|
||||
page * rowsPerPage,
|
||||
page * rowsPerPage + rowsPerPage
|
||||
)
|
||||
: rows
|
||||
).map((row) => (
|
||||
<tr key={row.exam_centre_code}>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
<a
|
||||
href={`/anomoly/reassigned/stats/${row.exam_centre_code}`}
|
||||
>
|
||||
{row.exam_centre_code}
|
||||
</a>
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.total_count}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.manual_verification_count}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{emptyRows > 0 && (
|
||||
<tr style={{ height: 41 * emptyRows }}>
|
||||
<td colSpan={3} aria-hidden />
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<CustomTablePagination
|
||||
rowsPerPageOptions={[5, 10, 25, { label: "All", value: -1 }]}
|
||||
colSpan={3}
|
||||
count={rows.length}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
slotProps={{
|
||||
select: {
|
||||
"aria-label": "rows per page",
|
||||
},
|
||||
actions: {
|
||||
showFirstButton: true,
|
||||
showLastButton: true,
|
||||
},
|
||||
}}
|
||||
onPageChange={handleChangePage}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
/>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</>
|
||||
)}
|
||||
{type === "IndividualReassignedStats" && (
|
||||
<>
|
||||
<h5 className="py-2">Exam Centre Code-Date Wise MetaData :</h5>
|
||||
<table aria-label="custom pagination table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Exam Centre Code</th>
|
||||
<th>Exam Date</th>
|
||||
<th>Subject Code</th>
|
||||
<th>Total Count</th>
|
||||
<th>Manual Verification Count</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(rowsPerPage > 0
|
||||
? rows.slice(
|
||||
page * rowsPerPage,
|
||||
page * rowsPerPage + rowsPerPage
|
||||
)
|
||||
: rows
|
||||
).map((row) => (
|
||||
<tr key={row.exam_centre_code}>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.exam_centre_code}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.exam_date}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.subject_code}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.total_count}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.manual_verification_needed_count}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{emptyRows > 0 && (
|
||||
<tr style={{ height: 41 * emptyRows }}>
|
||||
<td colSpan={3} aria-hidden />
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<CustomTablePagination
|
||||
rowsPerPageOptions={[5, 10, 25, { label: "All", value: -1 }]}
|
||||
colSpan={3}
|
||||
count={rows.length}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
slotProps={{
|
||||
select: {
|
||||
"aria-label": "rows per page",
|
||||
},
|
||||
actions: {
|
||||
showFirstButton: true,
|
||||
showLastButton: true,
|
||||
},
|
||||
}}
|
||||
onPageChange={handleChangePage}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
/>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</>
|
||||
)}
|
||||
{type === "PartAReassigned" && (
|
||||
<>
|
||||
<h5 className="py-2">Part-A Anomoly Data :</h5>
|
||||
<table aria-label="custom pagination table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>s3_path</th>
|
||||
<th>Barcode</th>
|
||||
<th>Subject Code</th>
|
||||
<th>Register Number</th>
|
||||
<th>Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(rowsPerPage > 0
|
||||
? rows.slice(
|
||||
page * rowsPerPage,
|
||||
page * rowsPerPage + rowsPerPage
|
||||
)
|
||||
: 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">
|
||||
{row.barcode}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.subject_code}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.register_number}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.type}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{emptyRows > 0 && (
|
||||
<tr style={{ height: 41 * emptyRows }}>
|
||||
<td colSpan={3} aria-hidden />
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<CustomTablePagination
|
||||
rowsPerPageOptions={[5, 10, 25, { label: "All", value: -1 }]}
|
||||
colSpan={3}
|
||||
count={rows.length}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
slotProps={{
|
||||
select: {
|
||||
"aria-label": "rows per page",
|
||||
},
|
||||
actions: {
|
||||
showFirstButton: true,
|
||||
showLastButton: true,
|
||||
},
|
||||
}}
|
||||
onPageChange={handleChangePage}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
/>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</>
|
||||
)}
|
||||
{type === "AttendenceAdditionalRecord" && (
|
||||
<>
|
||||
<h5 className="py-2">Part-A Anomoly Data :</h5>
|
||||
<table aria-label="custom pagination table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>qrcode</th>
|
||||
<th>Cover A</th>
|
||||
<th>Cover B</th>
|
||||
<th>Subject Code</th>
|
||||
<th>Total Students</th>
|
||||
<th>Total Present</th>
|
||||
<th>Total Absent</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(rowsPerPage > 0
|
||||
? rows.slice(
|
||||
page * rowsPerPage,
|
||||
page * rowsPerPage + rowsPerPage
|
||||
)
|
||||
: rows
|
||||
).map((row) => (
|
||||
<tr key={row.exam_centre_code}>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
<Link
|
||||
to={`/anomoly/attendence/additionalRecord/correction?qrcode=${row.qrcode}`}
|
||||
>
|
||||
{row?.qrcode}
|
||||
</Link>
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.coverA}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.coverB}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.subject_code}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.total_students}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.total_present}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.total_absent}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{emptyRows > 0 && (
|
||||
<tr style={{ height: 41 * emptyRows }}>
|
||||
<td colSpan={3} aria-hidden />
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<CustomTablePagination
|
||||
rowsPerPageOptions={[5, 10, 25, { label: "All", value: -1 }]}
|
||||
colSpan={3}
|
||||
count={rows.length}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
slotProps={{
|
||||
select: {
|
||||
"aria-label": "rows per page",
|
||||
},
|
||||
actions: {
|
||||
showFirstButton: true,
|
||||
showLastButton: true,
|
||||
},
|
||||
}}
|
||||
onPageChange={handleChangePage}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
/>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</>
|
||||
)}
|
||||
{type === "AdditionalSheet" && (
|
||||
<>
|
||||
<h5 className="py-2">Attendance Additional Sheet</h5>
|
||||
<div style={{ width: '200px', height: '50px', backgroundColor: 'lightblue', display: 'flex', justifyContent: 'center', alignItems: 'center', borderRadius: '5px' }}>
|
||||
<a
|
||||
style={{
|
||||
textDecoration: 'none',
|
||||
color: 'black',
|
||||
padding: '10px 20px',
|
||||
backgroundColor: 'white',
|
||||
border: '1px solid black',
|
||||
borderRadius: '5px',
|
||||
textAlign: 'center',
|
||||
display: 'inline-block'
|
||||
}}
|
||||
href="/assets/csv/additional_attedance_sheet_template.csv"
|
||||
download="additional_attedance_sheet_template.csv"
|
||||
>
|
||||
Download Template CSV
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<p>Please download the CSV file and by verifying the image type appropriately</p>
|
||||
|
||||
<table aria-label="custom pagination table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Image Name</th>
|
||||
<th>upload csv</th>
|
||||
<th>Image</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(rowsPerPage > 0
|
||||
? rows.slice(
|
||||
page * rowsPerPage,
|
||||
page * rowsPerPage + rowsPerPage
|
||||
)
|
||||
: rows
|
||||
).map((row) => (
|
||||
<tr key={row.exam_centre_code}>
|
||||
|
||||
<td style={{ width: 160 }} align="right">
|
||||
{row.image_name}
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
<div>
|
||||
<input type="file" accept=".csv" onChange={handleFileChange} />
|
||||
<button style={{width:'130px', height:'30px', fontSize:'12px', textAlign:'center'}} onClick={handleFileUpload}>Upload CSV</button>
|
||||
|
||||
</div>
|
||||
|
||||
</td>
|
||||
<td style={{ width: 160 }} align="right">
|
||||
<div>
|
||||
<span style={{cursor:'pointer', color:'blue'}} onClick={() => handleImageClick(row.s3_image_path)}>
|
||||
Preview Image
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>
|
||||
<a style={{textDecoration: 'none'}} href={`https://docs.exampaper.vidh.ai/${row.s3_image_path}`} download>
|
||||
Download Image
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
{/* <td style={{ width: 160 }} align="right">
|
||||
<Link
|
||||
to={`www.google.com`}
|
||||
>
|
||||
{row?.s3_image_path}
|
||||
</Link>
|
||||
</td> */}
|
||||
</tr>
|
||||
))}
|
||||
{emptyRows > 0 && (
|
||||
<tr style={{ height: 41 * emptyRows }}>
|
||||
<td colSpan={3} aria-hidden />
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<CustomTablePagination
|
||||
rowsPerPageOptions={[5, 10, 25, { label: "All", value: -1 }]}
|
||||
colSpan={3}
|
||||
count={rows.length}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
slotProps={{
|
||||
select: {
|
||||
"aria-label": "rows per page",
|
||||
},
|
||||
actions: {
|
||||
showFirstButton: true,
|
||||
showLastButton: true,
|
||||
},
|
||||
}}
|
||||
onPageChange={handleChangePage}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
/>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</>
|
||||
)}
|
||||
{
|
||||
isDialogOpen && (
|
||||
<ImageDialog
|
||||
imagePath={currentImagePath}
|
||||
setIsDialogOpen={setIsDialogOpen}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<Backdrop
|
||||
sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
||||
open={openLoader}
|
||||
>
|
||||
<CircularProgress color="inherit" />
|
||||
</Backdrop>
|
||||
|
||||
</Root>
|
||||
);
|
||||
}
|
||||
|
||||
const grey = {
|
||||
50: "#F3F6F9",
|
||||
100: "#E5EAF2",
|
||||
200: "#DAE2ED",
|
||||
300: "#C7D0DD",
|
||||
400: "#B0B8C4",
|
||||
500: "#9DA8B7",
|
||||
600: "#6B7A90",
|
||||
700: "#434D5B",
|
||||
800: "#303740",
|
||||
900: "#1C2025",
|
||||
};
|
||||
|
||||
const Root = styled("div")(
|
||||
({ theme }) => `
|
||||
table {
|
||||
font-family: 'IBM Plex Sans', sans-serif;
|
||||
font-size: 0.875rem;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
border: 1px solid ${theme.palette.mode === "dark" ? grey[800] : grey[200]};
|
||||
text-align: left;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: ${theme.palette.mode === "dark" ? grey[900] : "#fff"};
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
const CustomTablePagination = styled(TablePagination)`
|
||||
& .${classes.toolbar} {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
& .${classes.selectLabel} {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
& .${classes.displayedRows} {
|
||||
margin: 0;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
& .${classes.spacer} {
|
||||
display: none;
|
||||
}
|
||||
|
||||
& .${classes.actions} {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
`;
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
filename*,enter filename,"INSTUCTIONS: Present means mark '0', Absent means mark '1', Assigned means mark as 0, Reassigned means mark '1'. NOTE: all '*' fields are mandatory so please all '*' compulsory. Get filename from the UI which is as Imagename",,,
|
||||
,,,,,
|
||||
subject_code*,enter subject_code,,,,
|
||||
exam_centre_code*,enter exam_centre_code,,,,
|
||||
subject_title*,enter subject_title,,,,
|
||||
degree_with_branch*,enter degree_with_branch,,,,
|
||||
exam_date*,enter exam_date,,,,
|
||||
exam_date_session,enter exam_date_session,,,,
|
||||
cover_a,enter cover_a,,,,
|
||||
cover_b,enter cover_b,,,,
|
||||
,,,,,
|
||||
student_data,,,,,
|
||||
sno*,register_number*,Present/Absent*,Assigned/Reassigned*,reassigned_sno*,signed*
|
||||
1,,,,,
|
||||
|
Loading…
Reference in New Issue