149 lines
5.3 KiB
JavaScript
149 lines
5.3 KiB
JavaScript
import { Calculator, Scale, Printer, AlertCircle } from 'lucide-react';
|
|
import './ClassDetail.css';
|
|
|
|
export const ClassDetail = ({ classData, onClose }) => {
|
|
const majorGrades = classData.assignments.filter(a => a.isMajorGrade);
|
|
const minorGrades = classData.assignments.filter(a => !a.isMajorGrade);
|
|
|
|
const calculateAverage = (grades) => {
|
|
if (grades.length === 0) return '0.00%';
|
|
const sum = grades.reduce((acc, g) => {
|
|
const scoreMatch = g.score.match(/[\d.]+/);
|
|
const score = scoreMatch ? parseFloat(scoreMatch[0]) : 0;
|
|
return acc + score;
|
|
}, 0);
|
|
return `${(sum / grades.length).toFixed(2)}%`;
|
|
};
|
|
|
|
const getScoreColor = (score) => {
|
|
const scoreMatch = score.match(/[\d.]+/);
|
|
const numScore = scoreMatch ? parseFloat(scoreMatch[0]) : 0;
|
|
if (numScore >= 90) return 'score-excellent';
|
|
if (numScore >= 80) return 'score-good';
|
|
if (numScore >= 70) return 'score-average';
|
|
return 'score-poor';
|
|
};
|
|
|
|
const hasAlert = (score) => {
|
|
const scoreMatch = score.match(/[\d.]+/);
|
|
const numScore = scoreMatch ? parseFloat(scoreMatch[0]) : 0;
|
|
return numScore < 80;
|
|
};
|
|
|
|
return (
|
|
<div className="modal-overlay" onClick={onClose}>
|
|
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
|
|
{/* Header */}
|
|
<div className="modal-header">
|
|
<div className="header-content">
|
|
<div className="header-left">
|
|
<h2 className="class-name">{classData.className}</h2>
|
|
<div className="class-info">
|
|
<span>{classData.teacher}</span>
|
|
<span>•</span>
|
|
<span>{classData.period}</span>
|
|
<span>•</span>
|
|
<span className="category-badge">{classData.category}</span>
|
|
</div>
|
|
</div>
|
|
<div className="header-right">
|
|
<div className="final-grade">
|
|
{classData.finalGrades?.[0]?.grade || 'N/A'}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Action buttons */}
|
|
<div className="action-buttons">
|
|
<button className="action-btn">
|
|
<Calculator size={16} />
|
|
Calculations
|
|
</button>
|
|
<button className="action-btn">
|
|
<Scale size={16} />
|
|
Grading Scale
|
|
</button>
|
|
<button className="action-btn">
|
|
<Printer size={16} />
|
|
Print
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Assignments Table */}
|
|
<div className="assignments-container">
|
|
<table className="assignments-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Description</th>
|
|
<th>Due Date</th>
|
|
<th>Score</th>
|
|
<th>Attempts</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{/* Major Grades */}
|
|
{majorGrades.length > 0 && (
|
|
<>
|
|
<tr className="section-header major">
|
|
<td colSpan={2}>Major Grades</td>
|
|
<td>{calculateAverage(majorGrades)}</td>
|
|
<td></td>
|
|
</tr>
|
|
{majorGrades.map((assignment, idx) => (
|
|
<tr key={idx} className="assignment-row">
|
|
<td className="assignment-name">
|
|
{hasAlert(assignment.score) && (
|
|
<AlertCircle size={16} className="alert-icon" />
|
|
)}
|
|
<span>{assignment.name}</span>
|
|
</td>
|
|
<td className="due-date">{assignment.dueDate}</td>
|
|
<td className={`score ${getScoreColor(assignment.score)}`}>
|
|
{assignment.score}
|
|
</td>
|
|
<td className="attempts">{assignment.attempts}</td>
|
|
</tr>
|
|
))}
|
|
</>
|
|
)}
|
|
|
|
{/* Minor Grades */}
|
|
{minorGrades.length > 0 && (
|
|
<>
|
|
<tr className="section-header minor">
|
|
<td colSpan={2}>Minor Grades</td>
|
|
<td>{calculateAverage(minorGrades)}</td>
|
|
<td></td>
|
|
</tr>
|
|
{minorGrades.map((assignment, idx) => (
|
|
<tr key={idx} className="assignment-row">
|
|
<td className="assignment-name">
|
|
{hasAlert(assignment.score) && (
|
|
<AlertCircle size={16} className="alert-icon" />
|
|
)}
|
|
<span>{assignment.name}</span>
|
|
</td>
|
|
<td className="due-date">{assignment.dueDate}</td>
|
|
<td className={`score ${getScoreColor(assignment.score)}`}>
|
|
{assignment.score}
|
|
</td>
|
|
<td className="attempts">{assignment.attempts}</td>
|
|
</tr>
|
|
))}
|
|
</>
|
|
)}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
{/* Footer */}
|
|
<div className="modal-footer">
|
|
<button onClick={onClose} className="close-btn">
|
|
Close
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}; |