Your descriptive commit message

This commit is contained in:
Md. Parvej Hossain 2025-08-01 12:37:07 +06:00
parent c0b902a810
commit d5a534618c

View File

@ -329,7 +329,7 @@ function App() {
setChartError(false); setChartError(false);
}, [selectedStudent]); }, [selectedStudent]);
// FIXED PRINT FUNCTION - THE KEY CHANGE IS HERE // FIXED PRINT FUNCTION
const handlePrintResult = useCallback(() => { const handlePrintResult = useCallback(() => {
if (!selectedStudent) return; if (!selectedStudent) return;
@ -490,11 +490,10 @@ function App() {
printWindow.document.write(printContent); printWindow.document.write(printContent);
printWindow.document.close(); printWindow.document.close();
// FIXED: Removed the printWindow.close() call that was causing the issue
// Wait for the document to load before printing // Wait for the document to load before printing
printWindow.onload = function() { printWindow.onload = function() {
printWindow.print(); printWindow.print();
// DO NOT CLOSE THE WINDOW - Let the user close it when they're done // Do not close the window - let the user close it when they're done
}; };
}, [selectedStudent]); }, [selectedStudent]);
@ -724,34 +723,20 @@ function App() {
} }
}, [cgpaTrendData]); }, [cgpaTrendData]);
// Prepare data for CGPA Distribution Bar Chart // FIXED CGPA Distribution with cumulative counts
const cgpaDistributionData = useMemo(() => { const cgpaDistributionData = useMemo(() => {
const thresholds = [2.5, 3.0, 3.25, 3.5, 3.75, 3.8, 3.9, 4.0]; const thresholds = [2.5, 3.0, 3.25, 3.5, 3.75, 3.8, 3.9];
const distribution = [];
for (let i = 0; i < thresholds.length; i++) { return thresholds.map(threshold => {
const lowerBound = thresholds[i]; const studentsAboveThreshold = studentData.filter(student => student.cgpa > threshold);
const upperBound = (i + 1 < thresholds.length) ? thresholds[i + 1] : 4.01; // Upper bound for the last range
const studentsInThreshold = studentData.filter(student =>
student.cgpa >= lowerBound && student.cgpa < upperBound
);
let label; return {
if (i + 1 < thresholds.length) { range: threshold.toFixed(2),
label = `${lowerBound.toFixed(2)} - < ${upperBound.toFixed(2)}`; rangeLabel: `>${threshold.toFixed(2)}`,
} else { count: studentsAboveThreshold.length,
label = `≥ ${lowerBound.toFixed(2)}`; // For the last category (e.g., >= 4.0) students: studentsAboveThreshold.map(s => ({ name: s.name, roll: s.roll }))
} };
distribution.push({
threshold: lowerBound.toFixed(2), // Use lower bound for X-axis tick
rangeLabel: label, // Full range label for tooltip
count: studentsInThreshold.length,
students: studentsInThreshold.map(s => ({ name: s.name, roll: s.roll }))
}); });
}
return distribution;
}, []); }, []);
// Calculate overall statistics // Calculate overall statistics
@ -792,43 +777,55 @@ function App() {
<ResponsiveContainer width="100%" height={350}> <ResponsiveContainer width="100%" height={350}>
<LineChart <LineChart
data={selectedStudentGpaTrendData} data={selectedStudentGpaTrendData}
margin={{ top: 5, right: 10, left: 0, bottom: 5 }} margin={{ top: 20, right: 30, left: 20, bottom: 40 }}
style={{ fontFamily: 'Arial, sans-serif' }}
> >
<CartesianGrid strokeDasharray="3 3" stroke="#e0e0e0" /> <CartesianGrid
stroke="#e0e0e0"
strokeDasharray="3 3"
vertical={false}
/>
<XAxis <XAxis
dataKey="semester" dataKey="semester"
axisLine={false} tickMargin={10}
tickLine={false} tick={{ fontSize: 12, fill: '#666' }}
className="text-sm" axisLine={{ stroke: '#ccc' }}
tickMargin={8} tickLine={{ stroke: '#ccc' }}
tick={isMobile ? false : true}
angle={0}
textAnchor="middle"
dx={0}
dy={0}
/> />
<YAxis <YAxis
domain={selectedStudentGpaDomain} domain={selectedStudentGpaDomain}
allowDataOverflow={true} tickFormatter={(value) => value.toFixed(2)}
axisLine={false} tickMargin={10}
tickLine={false} tick={{ fontSize: 12, fill: '#666' }}
className="text-sm" axisLine={{ stroke: '#ccc' }}
tickFormatter={(value, index) => (index === 0 ? '' : value.toFixed(2))} tickLine={{ stroke: '#ccc' }}
tickMargin={8} />
angle={-90} <Tooltip
textAnchor="end" contentStyle={{
dx={-5} backgroundColor: '#fff',
dy={5} border: '1px solid #ddd',
padding: '8px',
boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
}}
cursor={{ stroke: 'rgba(0,0,0,0.1)' }}
/>
<Legend
iconType="circle"
wrapperStyle={{
bottom: 20,
left: 20,
fontSize: 12,
fontFamily: 'Arial, sans-serif'
}}
/> />
<Tooltip contentStyle={{ borderRadius: '8px', boxShadow: '0 4px 12px rgba(0,0,0,0.1)', border: 'none' }} />
<Legend wrapperStyle={{ paddingTop: '10px', fontSize: '14px' }} />
<Line <Line
type="monotone" type="monotone"
dataKey="gpa" dataKey="gpa"
stroke={chartColors[1]} stroke="#EC4899"
activeDot={{ r: 8 }} strokeWidth={2}
strokeWidth={3} dot={{ stroke: '#EC4899', strokeWidth: 2, r: 4 }}
name="GPA" activeDot={{ r: 6, stroke: '#EC4899', strokeWidth: 2 }}
name="GPA Trend"
/> />
</LineChart> </LineChart>
</ResponsiveContainer> </ResponsiveContainer>
@ -842,7 +839,7 @@ function App() {
</div> </div>
); );
} }
}, [selectedStudentGpaTrendData, selectedStudentGpaDomain, isMobile, chartError]); }, [selectedStudentGpaTrendData, selectedStudentGpaDomain, chartError]);
return ( return (
<div className="min-h-screen bg-gradient-to-br from-indigo-50 to-purple-100 p-4 sm:p-6 font-inter text-gray-800"> <div className="min-h-screen bg-gradient-to-br from-indigo-50 to-purple-100 p-4 sm:p-6 font-inter text-gray-800">
@ -899,7 +896,7 @@ function App() {
{searchTerm.trim() !== '' && filteredStudents.length === 0 && ( {searchTerm.trim() !== '' && filteredStudents.length === 0 && (
<div className="mt-6 p-4 bg-red-50 text-red-700 rounded-lg shadow-inner text-center"> <div className="mt-6 p-4 bg-red-50 text-red-700 rounded-lg shadow-inner text-center">
No students found matching "{searchTerm}". Please try a different name or roll. No students found matching "${searchTerm}". Please try a different name or roll.
</div> </div>
)} )}
</div> </div>
@ -976,7 +973,7 @@ function App() {
</div> </div>
</div> </div>
<div className="lg:col-span-2 bg-white p-6 rounded-xl shadow-lg border border-gray-200 flex flex-col justify-center"> <div className="lg:col-span-2 bg-white p-6 rounded-xl shadow-lg border border-gray-200">
<h2 className="text-2xl font-bold text-gray-800 mb-4 border-b pb-2 text-center" style={{ fontFamily: 'Georgia, serif', color: '#333', fontSize: '2rem' }}> <h2 className="text-2xl font-bold text-gray-800 mb-4 border-b pb-2 text-center" style={{ fontFamily: 'Georgia, serif', color: '#333', fontSize: '2rem' }}>
{selectedStudent.name ? `${selectedStudent.name}'s GPA Trend` : "Student's GPA Trend"} {selectedStudent.name ? `${selectedStudent.name}'s GPA Trend` : "Student's GPA Trend"}
</h2> </h2>
@ -1007,48 +1004,60 @@ function App() {
{/* Overall Charts - Now 50/50 split */} {/* Overall Charts - Now 50/50 split */}
<div className="lg:col-span-3 grid grid-cols-1 md:grid-cols-2 gap-8"> <div className="lg:col-span-3 grid grid-cols-1 md:grid-cols-2 gap-8">
{/* Overall Average GPA Trend by Semester */} {/* Overall Average GPA Trend by Semester */}
<div className="bg-white p-6 rounded-xl shadow-lg border border-gray-200 md:col-span-1 flex flex-col justify-center"> <div className="bg-white p-6 rounded-xl shadow-lg border border-gray-200 md:col-span-1">
<h2 className="text-2xl font-bold text-gray-800 mb-4 border-b pb-2 text-center">Overall Average GPA Trend by Semester</h2> <h2 className="text-2xl font-bold text-gray-800 mb-4 border-b pb-2 text-center">Overall Average GPA Trend by Semester</h2>
<ResponsiveContainer width="100%" height={300}> <ResponsiveContainer width="100%" height={300}>
<LineChart <LineChart
data={cgpaTrendData} data={cgpaTrendData}
margin={{ top: 5, right: 10, left: 0, bottom: 5 }} margin={{ top: 20, right: 30, left: 20, bottom: 40 }}
style={{ fontFamily: 'Arial, sans-serif' }}
> >
<CartesianGrid strokeDasharray="3 3" stroke="#e0e0e0" /> <CartesianGrid
stroke="#e0e0e0"
strokeDasharray="3 3"
vertical={false}
/>
<XAxis <XAxis
dataKey="semester" dataKey="semester"
axisLine={false} tickMargin={10}
tickLine={false} tick={{ fontSize: 12, fill: '#666' }}
className="text-sm" axisLine={{ stroke: '#ccc' }}
tickMargin={8} tickLine={{ stroke: '#ccc' }}
tick={isMobile ? false : true}
angle={0}
textAnchor="middle"
dx={0}
dy={0}
/> />
<YAxis <YAxis
domain={overallGpaDomain} domain={overallGpaDomain}
allowDataOverflow={true} tickFormatter={(value) => value.toFixed(2)}
axisLine={false} tickMargin={10}
tickLine={false} tick={{ fontSize: 12, fill: '#666' }}
className="text-sm" axisLine={{ stroke: '#ccc' }}
tickFormatter={(value, index) => (index === 0 ? '' : value.toFixed(2))} tickLine={{ stroke: '#ccc' }}
tickMargin={8} />
angle={-90} <Tooltip
textAnchor="end" contentStyle={{
dx={-5} backgroundColor: '#fff',
dy={5} border: '1px solid #ddd',
padding: '8px',
boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
}}
cursor={{ stroke: 'rgba(0,0,0,0.1)' }}
/>
<Legend
iconType="circle"
wrapperStyle={{
bottom: 20,
left: 20,
fontSize: 12,
fontFamily: 'Arial, sans-serif'
}}
/> />
<Tooltip contentStyle={{ borderRadius: '8px', boxShadow: '0 4px 12px rgba(0,0,0,0.1)', border: 'none' }} />
<Legend wrapperStyle={{ paddingTop: '10px', fontSize: '14px' }} />
<Line <Line
type="monotone" type="monotone"
dataKey="averageGpa" dataKey="averageGpa"
stroke={chartColors[1]} stroke="#EC4899"
activeDot={{ r: 8 }} strokeWidth={2}
strokeWidth={3} dot={{ stroke: '#EC4899', strokeWidth: 2, r: 4 }}
activeDot={{ r: 6, stroke: '#EC4899', strokeWidth: 2 }}
name="Average GPA" name="Average GPA"
/> />
</LineChart> </LineChart>
@ -1056,20 +1065,49 @@ function App() {
</div> </div>
{/* CGPA Distribution (Number of Students) */} {/* CGPA Distribution (Number of Students) */}
<div className="bg-white p-6 rounded-xl shadow-lg border border-gray-200 md:col-span-1 flex flex-col justify-center"> <div className="bg-white p-6 rounded-xl shadow-lg border border-gray-200 md:col-span-1">
<h2 className="text-2xl font-bold text-gray-800 mb-4 border-b pb-2 text-center">CGPA Distribution (Number of Students)</h2> <h2 className="text-2xl font-bold text-gray-800 mb-4 border-b pb-2 text-center">CGPA Distribution (Number of Students)</h2>
<ResponsiveContainer width="100%" height={300}> <ResponsiveContainer width="100%" height={300}>
<BarChart <BarChart
data={cgpaDistributionData} data={cgpaDistributionData}
margin={{ top: 20, right: 10, left: 10, bottom: 5 }} margin={{ top: 20, right: 30, left: 40, bottom: 40 }}
> >
<CartesianGrid strokeDasharray="3 3" stroke="#e0e0e0" /> <CartesianGrid
<XAxis dataKey="threshold" axisLine={false} tickLine={false} className="text-sm" tickMargin={8} /> stroke="#e0e0e0"
<YAxis allowDecimals={false} axisLine={false} tickLine={false} className="text-sm" tickMargin={8} /> strokeDasharray="3 3"
/>
<XAxis
dataKey="range"
tickMargin={10}
tick={{ fontSize: 12, fill: '#666' }}
axisLine={{ stroke: '#ccc' }}
tickLine={{ stroke: '#ccc' }}
/>
<YAxis
allowDecimals={false}
tickMargin={10}
tick={{ fontSize: 12, fill: '#666' }}
axisLine={{ stroke: '#ccc' }}
tickLine={{ stroke: '#ccc' }}
/>
<Tooltip cursor={{ fill: 'rgba(0,0,0,0.05)' }} content={<CustomTooltip />} /> <Tooltip cursor={{ fill: 'rgba(0,0,0,0.05)' }} content={<CustomTooltip />} />
<Legend wrapperStyle={{ paddingTop: '10px', fontSize: '14px' }} /> <Legend
<Bar dataKey="count" fill={chartColors[2]} name="Students" radius={[10, 10, 0, 0]} /> iconType="square"
wrapperStyle={{
bottom: 20,
left: 20,
fontSize: 12,
fontFamily: 'Arial, sans-serif'
}}
/>
<Bar
dataKey="count"
fill="#10B981"
name="Students"
radius={[10, 10, 0, 0]}
barSize={30} // Increased bar width
/>
</BarChart> </BarChart>
</ResponsiveContainer> </ResponsiveContainer>
</div> </div>