import React, { useState, useEffect, useMemo } from 'react'; import { Save, UserCheck, Clock, BookOpen, Calendar, Users, CheckCircle, RotateCcw, UserX, ClipboardList, User } from 'lucide-react'; import { saveClassJournalEntry } from '../services/apiService'; import { Student, Teacher, AttendanceDetail, AuthUser, Class } from '../types'; interface ClassJournalFormProps { onSuccess: () => void; students: Student[]; teachers: Teacher[]; subjects: string[]; classes?: Class[]; // Optional: classes from database currentUser: AuthUser; } const ClassJournalForm: React.FC = ({ onSuccess, students, teachers, subjects, classes = [], currentUser }) => { const [loading, setLoading] = useState(false); const [selectedClass, setSelectedClass] = useState(''); // Form State const [formData, setFormData] = useState({ teacherName: '', subject: '', date: new Date().toISOString().split('T')[0], startTime: '1', endTime: '2', teacherPresence: 'Hadir' as 'Hadir' | 'Tugas' | 'Tidak Hadir', notes: '', classSecretary: '' }); // Pre-fill class if user is Secretary useEffect(() => { if (currentUser.role === 'SEKRETARIS' && currentUser.className) { setSelectedClass(currentUser.className); setFormData(prev => ({ ...prev, classSecretary: currentUser.name })); } }, [currentUser]); // Attendance State: studentId -> Status const [attendanceMap, setAttendanceMap] = useState>({}); // Get Unique Classes - prefer classes prop, fallback to extracting from students const availableClasses = useMemo(() => { // If classes prop is provided and has data, use it if (classes && classes.length > 0) { return classes.map(c => c.name).sort(); } // Fallback: extract unique class names from students const classSet = new Set(students.map(s => s.className).filter(Boolean)); return Array.from(classSet).sort(); }, [classes, students]); const classStudents = useMemo(() => { if (!selectedClass) return []; return students .filter(s => s.className === selectedClass) .sort((a, b) => a.name.localeCompare(b.name)); }, [selectedClass, students]); // Reset attendance and secretary when class changes useEffect(() => { const newMap: Record = {}; classStudents.forEach(s => { newMap[s.id] = 'H'; }); setAttendanceMap(newMap); // Only reset secretary if not logged in as one if (currentUser.role !== 'SEKRETARIS') { setFormData(prev => ({ ...prev, classSecretary: '' })); } }, [classStudents, currentUser.role]); const handleChange = (e: React.ChangeEvent) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); }; const handleAttendanceChange = (studentId: string, status: 'H' | 'S' | 'I' | 'A' | 'D') => { setAttendanceMap(prev => ({ ...prev, [studentId]: status })); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!formData.teacherName || !selectedClass || !formData.subject || !formData.classSecretary) { alert('Mohon lengkapi data Guru, Mapel, Kelas, dan Sekretaris.'); return; } setLoading(true); let present = 0, sakit = 0, izin = 0, alpha = 0, disp = 0; const attendanceDetailsList: AttendanceDetail[] = []; classStudents.forEach(student => { const status = attendanceMap[student.id] || 'H'; if (status === 'H') present++; else if (status === 'S') { sakit++; } else if (status === 'I') { izin++; } else if (status === 'A') { alpha++; } else if (status === 'D') { disp++; } if (status !== 'H') { attendanceDetailsList.push({ studentName: student.name, status: status }); } }); const attendancePayload = attendanceDetailsList.length > 0 ? attendanceDetailsList : "NIHIL"; const success = await saveClassJournalEntry({ teacherName: formData.teacherName, subject: formData.subject, className: selectedClass, teacherPresence: formData.teacherPresence, classSecretary: formData.classSecretary, ...formData, studentsPresent: present + disp, sakit, izin, alpha, dispen: disp, attendanceDetails: attendancePayload, }); setLoading(false); if (success) { alert('Jurnal Kelas berhasil disimpan!'); onSuccess(); } else { alert('Gagal menyimpan jurnal. Cek koneksi internet.'); } }; const periods = Array.from({ length: 10 }, (_, i) => i + 1); return (

Input Jurnal Kelas

Diisi oleh Sekretaris atau Piket Kelas

{/* Header Grid */}
{selectedClass && (
)} {/* Placeholder if no class selected to maintain grid layout */} {!selectedClass &&
}
{/* Presence & Time */}
{['Hadir', 'Tugas', 'Tidak Hadir'].map((status) => ( ))}
-

{/* Student Attendance Table */}

Presensi Siswa

Total Siswa: {classStudents.length}
{!selectedClass ? (
Silahkan pilih kelas terlebih dahulu untuk memuat daftar siswa.
) : (
{classStudents.map((student, index) => { const status = attendanceMap[student.id] || 'H'; const isAbsent = status !== 'H'; return ( ); })}
No Nama Siswa Sakit Izin Alpha Disp. Reset
{index + 1} {student.name}
{student.nis}
handleAttendanceChange(student.id, 'S')} className="w-5 h-5 accent-yellow-500 cursor-pointer" /> handleAttendanceChange(student.id, 'I')} className="w-5 h-5 accent-blue-500 cursor-pointer" /> handleAttendanceChange(student.id, 'A')} className="w-5 h-5 accent-red-500 cursor-pointer" /> handleAttendanceChange(student.id, 'D')} className="w-5 h-5 accent-purple-500 cursor-pointer" /> {isAbsent && ( )}
)}