Add Dark Mode, Password Hashing for better security , Settings Page, Policy PDF in Policy section,UI Changes
This commit is contained in:
@@ -15,7 +15,7 @@ import {
|
||||
Tooltip,
|
||||
Legend,
|
||||
} from "chart.js";
|
||||
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
||||
import ChartDataLabels from "chartjs-plugin-datalabels";
|
||||
import Table from "./Table";
|
||||
import { PDFDownloadLink, PDFViewer } from "@react-pdf/renderer";
|
||||
import ApprovalVsRejectionTrends from "./map";
|
||||
@@ -46,19 +46,24 @@ function Charts({ reportData }) {
|
||||
);
|
||||
}
|
||||
|
||||
const { acceptedApplications, rejectedApplications, pendingApplications } = data;
|
||||
const { acceptedApplications, rejectedApplications, pendingApplications } =
|
||||
data;
|
||||
|
||||
const tableData = [];
|
||||
const groupedData = {};
|
||||
|
||||
// --- Data Processing for Table --- (Simple aggregation logic)
|
||||
if (acceptedApplications) {
|
||||
for (const item of acceptedApplications) {
|
||||
const { institute, department, formData } = item;
|
||||
const { totalExpense } = formData;
|
||||
|
||||
// Initialize institute object if not exists
|
||||
if (!groupedData[institute]) {
|
||||
groupedData[institute] = {};
|
||||
}
|
||||
|
||||
// If filtering by specific institute, we group by Department (e.g. Computer, IT, Mech)
|
||||
if (query.institute) {
|
||||
if (!groupedData[institute][department]) {
|
||||
groupedData[institute][department] = {
|
||||
@@ -67,11 +72,12 @@ function Charts({ reportData }) {
|
||||
};
|
||||
}
|
||||
|
||||
// Aggregate the data
|
||||
// Add expense and increment count
|
||||
groupedData[institute][department].totalExpense +=
|
||||
parseFloat(totalExpense); // Summing the expenses
|
||||
parseFloat(totalExpense);
|
||||
groupedData[institute][department].applications += 1;
|
||||
} else {
|
||||
// If viewing all institutes, we group by Institute (e.g. KJSCE, KJSIM)
|
||||
if (!groupedData[institute].applications) {
|
||||
groupedData[institute] = {
|
||||
totalExpense: 0,
|
||||
@@ -79,38 +85,40 @@ function Charts({ reportData }) {
|
||||
};
|
||||
}
|
||||
|
||||
// Aggregate the data
|
||||
groupedData[institute].totalExpense += parseFloat(totalExpense); // Summing the expenses
|
||||
// Add expense and increment count
|
||||
groupedData[institute].totalExpense += parseFloat(totalExpense);
|
||||
groupedData[institute].applications += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Transform grouped data into desired table format
|
||||
// --- Transform Groups to Array for Display ---
|
||||
if (query.institute) {
|
||||
// Loop through departments for the selected institute
|
||||
for (const institute in groupedData) {
|
||||
for (const department in groupedData[institute]) {
|
||||
const departmentData = groupedData[institute][department];
|
||||
|
||||
tableData.push({
|
||||
id: tableData.length + 1,
|
||||
Stream: department,
|
||||
Scholarship: departmentData.applications, // Assuming each application is one scholarship
|
||||
Purpose_of_Travel: departmentData.purposeOfTravel,
|
||||
Funds: departmentData.totalExpense.toFixed(2), // Formatting funds to 2 decimal places
|
||||
Stream: department, // 'Stream' here refers to the Department name
|
||||
Scholarship: departmentData.applications, // Number of applications
|
||||
Purpose_of_Travel: departmentData.purposeOfTravel, // (Placeholder)
|
||||
Funds: departmentData.totalExpense.toFixed(2), // Total money spent
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Loop through all institutes
|
||||
for (const institute in groupedData) {
|
||||
const instituteData = groupedData[institute];
|
||||
|
||||
tableData.push({
|
||||
id: tableData.length + 1,
|
||||
Stream: institute,
|
||||
Scholarship: instituteData.applications, // Assuming each application is one scholarship
|
||||
Stream: institute, // 'Stream' here is the Institute name
|
||||
Scholarship: instituteData.applications, // Number of applications
|
||||
Purpose_of_Travel: instituteData.purposeOfTravel,
|
||||
Funds: instituteData.totalExpense.toFixed(2), // Formatting funds to 2 decimal places
|
||||
Funds: instituteData.totalExpense.toFixed(2), // Total money spent
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -122,6 +130,8 @@ function Charts({ reportData }) {
|
||||
isLoading: false,
|
||||
});
|
||||
|
||||
// --- Chart Configuration (Preserved for future use) ---
|
||||
|
||||
// Line Chart Data and Options
|
||||
const lineOptions = {
|
||||
responsive: true,
|
||||
@@ -281,80 +291,86 @@ function Charts({ reportData }) {
|
||||
],
|
||||
};
|
||||
|
||||
// const barChartRef = useRef();
|
||||
// const pieChartRef1 = useRef();
|
||||
// const pieChartRef2 = useRef();
|
||||
const barChartRef = useRef();
|
||||
const pieChartRef1 = useRef();
|
||||
const pieChartRef2 = useRef();
|
||||
|
||||
// const loadChartsInPdf = () => {
|
||||
// const barChartInstance = barChartRef.current;
|
||||
// const pieChartInstance1 = pieChartRef1.current;
|
||||
// const pieChartInstance2 = pieChartRef2.current;
|
||||
// Note: Chart generation logic for PDF is currently disabled as we focus on the Table view.
|
||||
// Uncomment this when we are ready to integrate charts into the PDF report.
|
||||
/*
|
||||
const loadChartsInPdf = () => {
|
||||
const barChartInstance = barChartRef.current;
|
||||
const pieChartInstance1 = pieChartRef1.current;
|
||||
const pieChartInstance2 = pieChartRef2.current;
|
||||
|
||||
// if (barChartInstance) {
|
||||
// const barBase64Image = barChartInstance.toBase64Image();
|
||||
// setChartImages((prevImages) => ({
|
||||
// ...prevImages,
|
||||
// barChart: barBase64Image,
|
||||
// }));
|
||||
// }
|
||||
if (barChartInstance) {
|
||||
const barBase64Image = barChartInstance.toBase64Image();
|
||||
setChartImages((prevImages) => ({
|
||||
...prevImages,
|
||||
barChart: barBase64Image,
|
||||
}));
|
||||
}
|
||||
|
||||
// if (pieChartInstance1) {
|
||||
// const pieBase64Image = pieChartInstance1.toBase64Image();
|
||||
// setChartImages((prevImages) => ({
|
||||
// ...prevImages,
|
||||
// pieChart1: pieBase64Image,
|
||||
// }));
|
||||
// }
|
||||
if (pieChartInstance1) {
|
||||
const pieBase64Image = pieChartInstance1.toBase64Image();
|
||||
setChartImages((prevImages) => ({
|
||||
...prevImages,
|
||||
pieChart1: pieBase64Image,
|
||||
}));
|
||||
}
|
||||
|
||||
// if (pieChartInstance2) {
|
||||
// const pieBase64Image = pieChartInstance2.toBase64Image();
|
||||
// setChartImages((prevImages) => ({
|
||||
// ...prevImages,
|
||||
// pieChart2: pieBase64Image,
|
||||
// }));
|
||||
// }
|
||||
// };
|
||||
if (pieChartInstance2) {
|
||||
const pieBase64Image = pieChartInstance2.toBase64Image();
|
||||
setChartImages((prevImages) => ({
|
||||
...prevImages,
|
||||
pieChart2: pieBase64Image,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// useEffect(() => {
|
||||
// setChartImages((prevImages) => ({ ...prevImages, isLoading: true }));
|
||||
useEffect(() => {
|
||||
setChartImages((prevImages) => ({ ...prevImages, isLoading: true }));
|
||||
|
||||
// const handleRender = () => {
|
||||
// loadChartsInPdf();
|
||||
// setChartImages((prevImages) => ({ ...prevImages, isLoading: false }));
|
||||
// };
|
||||
const handleRender = () => {
|
||||
loadChartsInPdf();
|
||||
setChartImages((prevImages) => ({ ...prevImages, isLoading: false }));
|
||||
};
|
||||
|
||||
// const barChartInstance = barChartRef.current;
|
||||
// const pieChartInstance1 = pieChartRef1.current;
|
||||
// const pieChartInstance2 = pieChartRef2.current;
|
||||
const barChartInstance = barChartRef.current;
|
||||
const pieChartInstance1 = pieChartRef1.current;
|
||||
const pieChartInstance2 = pieChartRef2.current;
|
||||
|
||||
// if (barChartInstance) {
|
||||
// barChartInstance.options.animation.onComplete = handleRender;
|
||||
// }
|
||||
if (barChartInstance) {
|
||||
barChartInstance.options.animation.onComplete = handleRender;
|
||||
}
|
||||
|
||||
// if (pieChartInstance1) {
|
||||
// pieChartInstance1.options.animation.onComplete = handleRender;
|
||||
// }
|
||||
if (pieChartInstance1) {
|
||||
pieChartInstance1.options.animation.onComplete = handleRender;
|
||||
}
|
||||
|
||||
// if (pieChartInstance2) {
|
||||
// pieChartInstance2.options.animation.onComplete = handleRender;
|
||||
// }
|
||||
if (pieChartInstance2) {
|
||||
pieChartInstance2.options.animation.onComplete = handleRender;
|
||||
}
|
||||
|
||||
// return () => {
|
||||
// if (barChartInstance) {
|
||||
// barChartInstance.options.animation.onComplete = null;
|
||||
// }
|
||||
// if (pieChartInstance1) {
|
||||
// pieChartInstance1.options.animation.onComplete = null;
|
||||
// }
|
||||
// if (pieChartInstance2) {
|
||||
// pieChartInstance2.options.animation.onComplete = null;
|
||||
// }
|
||||
// };
|
||||
// }, []);
|
||||
return () => {
|
||||
if (barChartInstance) {
|
||||
barChartInstance.options.animation.onComplete = null;
|
||||
}
|
||||
if (pieChartInstance1) {
|
||||
pieChartInstance1.options.animation.onComplete = null;
|
||||
}
|
||||
if (pieChartInstance2) {
|
||||
pieChartInstance2.options.animation.onComplete = null;
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
*/
|
||||
|
||||
return (
|
||||
<div className="p-10">
|
||||
<h1 className="text-3xl mb-6">Travel Policy Report</h1>
|
||||
<h1 className="text-3xl mb-6 text-gray-800 dark:text-google-text">
|
||||
Travel Policy Report
|
||||
</h1>
|
||||
|
||||
{/* Container for all three charts */}
|
||||
{/* <div className="grid grid-cols-1 md:grid-cols-1 lg:grid-cols-[2fr,1fr] gap-6">
|
||||
@@ -387,9 +403,11 @@ function Charts({ reportData }) {
|
||||
|
||||
<div className="flex flex-col gap-10 items-center justify-center my-10">
|
||||
<div className="w-full">
|
||||
{/* Reuse the Table component to show aggregated data */}
|
||||
<Table tableData={tableData} />
|
||||
</div>
|
||||
{/*
|
||||
|
||||
{/*
|
||||
<div>
|
||||
<Pie options={pie_Options} data={pie_Data} ref={pieChartRef2} />
|
||||
</div> */}
|
||||
@@ -428,9 +446,11 @@ function Charts({ reportData }) {
|
||||
}
|
||||
</PDFDownloadLink>
|
||||
|
||||
<PDFViewer style={{ width: "70vw", height: "100vh" }}>
|
||||
<ReportPDF tableData={tableData} chartImages={chartImages} />
|
||||
</PDFViewer>
|
||||
<div className="mt-8 hidden md:block">
|
||||
<PDFViewer style={{ width: "70vw", height: "100vh" }}>
|
||||
<ReportPDF tableData={tableData} chartImages={chartImages} />
|
||||
</PDFViewer>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user