import React, { useEffect, useRef, useState } from 'react';
import { Bar } from 'react-chartjs-2';
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js';
import jsPDF from 'jspdf';
import { Container } from "react-bootstrap";
import { SERVER_URL } from '../App';
// Register necessary chart components
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale);
interface Props {
dir: string;
chartId: string;
queryDept: string;
queryId: string;
queryYear: string;
}
const SectionsBarChart: React.FC<Props> = ({ dir, chartId, queryDept, queryId, queryYear }) => {
const chartRef = useRef<any>(null);
const [courses, setCourses] = useState<any[]>([]);
// const port = 4321;
// const SERVER_URL = `http://localhost:${port}`;
useEffect(() => {
const querySections = {
"WHERE": {
"AND": [
{ "EQ": { [`${chartId}_year`]: Number(queryYear === "Year" ? -1 : queryYear)} },
{ "IS": { [`${chartId}_dept`]: queryDept } },
{ "IS": { [`${chartId}_id`]: queryId } }
]
},
"OPTIONS": {
"COLUMNS": [
`${chartId}_uuid`,
`${chartId}_instructor`,
`${chartId}_avg`,
`${chartId}_pass`,
`${chartId}_fail`
],
"ORDER": { "dir": dir, "keys": [`${chartId}_avg`] }
}
};
const requestOptions = {
method: "POST",
body: JSON.stringify(querySections),
headers: { 'Content-Type': 'application/json' }
};
fetch(`${SERVER_URL}/query`, requestOptions)
.then((res) => {
if (!res.ok) {
return "";
throw new Error(`Failed to query: ${res.statusText}`);
}
return res.json();
})
.then((data) => {
if (data === "") {
return setCourses([]);
}
//console.log("Received data: SectionsBarChart", data);
setCourses(data.result);
})
.catch((_error) => {
//console.error("Error:", error);
});
}, [chartId, dir, queryDept, queryId, queryYear]);
let labels = courses.map(course => `${course[`${chartId}_uuid`]} (${course[`${chartId}_instructor`]})`);
let averages = courses.map(course => course[`${chartId}_avg`]);
let passes = courses.map(course => course[`${chartId}_pass`]);
let failures = courses.map(course => course[`${chartId}_fail`]);
let combined = labels.map((id, index) => ({
label: id,
average: averages[index],
pass: passes[index],
fail: failures[index]
}));
combined = combined.sort((a, b) => a.average - b.average).slice(-10);
labels = combined.map(item => item.label);
averages = combined.map(item => item.average);
passes = combined.map(item => item.pass);
failures = combined.map(item => item.fail);
const data = {
labels,
datasets: [
{
label: 'Average Score',
data: averages,
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 2,
},
{
label: 'Pass Count',
data: passes,
backgroundColor: 'rgba(75, 192, 192, 0.6)',
borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 2,
},
{
label: 'Fail Count',
data: failures,
backgroundColor: 'rgba(255, 0, 0, 0.6)',
borderColor: 'rgba(75, 7, 192, 1)',
borderWidth: 2,
}
]
};
const options = {
responsive: true,
plugins: {
tooltip: {
callbacks: {
label: (tooltipItem: any) => `Value: ${tooltipItem.raw}`
},
},
legend: { display: true },
}
};
const downloadPDF = () => {
if (!chartRef.current) return;
const chartInstance = chartRef.current;
const chartImage = chartInstance.toBase64Image();
const pdf = new jsPDF('landscape');
pdf.addImage(chartImage, 'PNG', 15, 20, 250, 120);
pdf.save('SectionsBarChart.pdf');
};
return (
<Container className="mt-4 container-xxl">
<h3 className="text-center">Sections</h3>
<Bar ref={chartRef} data={data} options={options} />
<button className="btn btn-primary mt-3" onClick={downloadPDF}>Download PDF</button>
</Container>
);
};
export default SectionsBarChart;