import response from "../../response.js"; import models from "../../models/index.js"; export const getMonitorings = async (req, res) => { try { const monitoring = await models.Monitoring.findAll(); response(200, monitoring, "Success", res); } catch (error) { console.log(error); response(500, null, "Error retrieving monitoring data!", res); } }; export const getMonitoringById = async (req, res) => { try { const { id } = req.params; const monitoring = await models.Monitoring.findByPk(id); if (!monitoring) { return response(404, null, "Monitoring data not found", res); } response(200, monitoring, "Success", res); } catch (error) { console.log(error); response(500, null, "Internal Server Error", res); } }; export const createMonitoring = async (req) => { const { ID_STUDENT_LEARNING } = req.body; if (!req.user) { throw new Error("User not authenticated"); } if (!ID_STUDENT_LEARNING) { throw new Error("Student Learning ID is required"); } try { const existingMonitoring = await models.Monitoring.findOne({ where: { ID_STUDENT_LEARNING: ID_STUDENT_LEARNING }, }); if (existingMonitoring) { return existingMonitoring.toJSON(); } const stdLearning = await models.StdLearning.findByPk(ID_STUDENT_LEARNING); if (!stdLearning) { throw new Error("Student learning data not found"); } const userID = stdLearning.ID; const student = await models.Student.findOne({ where: { ID: userID } }); if (!student) { throw new Error("Student data not found"); } const { ID_SISWA } = student; const studentClass = await models.Student.findOne({ where: { ID_SISWA: ID_SISWA }, attributes: ["ID_CLASS"], }); const ID_CLASS = studentClass && studentClass.ID_CLASS ? studentClass.ID_CLASS : null; const newMonitoring = await models.Monitoring.create({ ID_STUDENT_LEARNING, ID_CLASS, }); return newMonitoring.toJSON(); } catch (error) { console.error(error); throw new Error("Internal Server Error"); } }; export const updateMonitoringClass = async ({ ID_STUDENT_LEARNING, ID_CLASS, }) => { if (!ID_STUDENT_LEARNING || !ID_CLASS) { throw new Error("Student Learning ID and Class ID are required"); } try { const monitoring = await models.Monitoring.findOne({ where: { ID_STUDENT_LEARNING }, }); if (!monitoring) { throw new Error("Monitoring data not found"); } monitoring.ID_CLASS = ID_CLASS; await monitoring.save(); return monitoring; } catch (error) { console.error(error); throw error; } }; export const monitoringStudentsProgress = async (req, res) => { const { page = 1, limit = 10, search = "", sort = "time" } = req.query; try { const { count, rows: monitorings } = await models.Monitoring.findAndCountAll({ include: [ { model: models.StdLearning, as: "stdLearningMonitoring", include: [ { model: models.User, as: "learningUser", attributes: ["NAME_USERS"], include: [ { model: models.Student, as: "students", attributes: ["NISN"], include: [ { model: models.Class, as: "studentClass", attributes: ["NAME_CLASS"], }, ], }, ], }, { model: models.Level, as: "level", attributes: ["NAME_LEVEL"], include: [ { model: models.Topic, as: "levelTopic", attributes: ["NAME_TOPIC"], include: [ { model: models.Section, as: "topicSection", attributes: ["NAME_SECTION"], }, ], }, ], }, ], }, ], where: { ...(search && { [models.Op.or]: [ { "$stdLearningMonitoring.learningUser.students.NISN$": { [models.Op.like]: `%${search}%`, }, }, { "$stdLearningMonitoring.learningUser.NAME_USERS$": { [models.Op.like]: `%${search}%`, }, }, { "$stdLearningMonitoring.level.levelTopic.topicSection.NAME_SECTION$": { [models.Op.like]: `%${search}%`, }, }, { "$stdLearningMonitoring.level.levelTopic.NAME_TOPIC$": { [models.Op.like]: `%${search}%`, }, }, ], }), }, distinct: true, }); const formattedResult = monitorings.map((monitoring) => ({ ID_MONITORING: monitoring.ID_MONITORING, NISN: monitoring.stdLearningMonitoring?.learningUser?.students?.NISN, NAME_USERS: monitoring.stdLearningMonitoring?.learningUser?.NAME_USERS, NAME_SECTION: monitoring.stdLearningMonitoring?.level?.levelTopic?.topicSection ?.NAME_SECTION, NAME_TOPIC: monitoring.stdLearningMonitoring?.level?.levelTopic?.NAME_TOPIC, NAME_CLASS: monitoring.stdLearningMonitoring?.learningUser?.students?.studentClass ?.NAME_CLASS ?? null, })); if (sort === "nisn") { formattedResult.sort((a, b) => a.NISN.localeCompare(b.NISN)); } else if (sort === "name") { formattedResult.sort((a, b) => a.NAME_USERS.localeCompare(b.NAME_USERS)); } else if (sort === "section") { formattedResult.sort((a, b) => a.NAME_SECTION.localeCompare(b.NAME_SECTION) ); } else if (sort === "topic") { formattedResult.sort((a, b) => a.NAME_TOPIC.localeCompare(b.NAME_TOPIC)); } else { formattedResult.sort((a, b) => new Date(b.TIME) - new Date(a.TIME)); } const paginatedResult = formattedResult.slice( (page - 1) * limit, page * limit ); const totalPages = Math.ceil(count / limit); const currentPage = parseInt(page); response( 200, { monitorings: paginatedResult, currentPage, totalPages, totalItems: count, }, "Success retrieving student monitoring progress!", res ); } catch (error) { console.error(error); response(500, null, "Error retrieving student monitoring progress!", res); } }; export const monitoringStudentProgressById = async (req, res) => { const { id } = req.params; const { page = 1, limit = 10, search = "", sort = "start" } = req.query; try { const monitoring = await models.Monitoring.findOne({ where: { ID_MONITORING: id }, include: [ { model: models.StdLearning, as: "stdLearningMonitoring", attributes: [ "ID", "ID_LEVEL", "SCORE", "FEEDBACK_STUDENT", "STUDENT_START", "STUDENT_FINISH", "ID_STUDENT_LEARNING", ], include: [ { model: models.Level, as: "level", attributes: ["ID_TOPIC", "NAME_LEVEL"], include: [ { model: models.Topic, as: "levelTopic", attributes: ["NAME_TOPIC"], include: [ { model: models.Section, as: "topicSection", attributes: ["NAME_SECTION"], }, ], }, ], }, { model: models.User, as: "learningUser", attributes: ["NAME_USERS"], include: [ { model: models.Student, as: "students", attributes: ["NISN"], }, ], }, ], }, ], }); if (!monitoring) { return response(404, null, "Monitoring data not found!", res); } const stdLearning = monitoring.stdLearningMonitoring; if (!stdLearning || stdLearning.length === 0) { return response(404, null, "No student learning data found!", res); } const userID = stdLearning.ID; const topicID = stdLearning.level.ID_TOPIC; const studentName = stdLearning.learningUser.NAME_USERS; const nisn = stdLearning.learningUser.students.NISN; const topicName = stdLearning.level.levelTopic.NAME_TOPIC; const sectionName = stdLearning.level.levelTopic.topicSection.NAME_SECTION; // Fetch levels with pagination, search, and sort const levels = await models.StdLearning.findAndCountAll({ where: { ID: userID, ...(search && { [models.Op.or]: [ { "$level.NAME_LEVEL$": { [models.Op.like]: `%${search}%` }, }, { SCORE: { [models.Op.like]: `%${search}%` }, }, { FEEDBACK_STUDENT: { [models.Op.like]: `%${search}%` }, }, // { // [models.Sequelize.fn('DATE_FORMAT', models.Sequelize.col('STUDENT_START'), '%Y-%m-%d')]: { // [models.Op.like]: `%${search}%`, // }, // }, // { // [models.Sequelize.fn('DATE_FORMAT', models.Sequelize.col('STUDENT_FINISH'), '%Y-%m-%d')]: { // [models.Op.like]: `%${search}%`, // }, // }, ], }), }, include: [ { model: models.Level, as: "level", attributes: ["NAME_LEVEL", "ID_TOPIC"], where: { ID_TOPIC: topicID, }, }, ], attributes: [ "SCORE", "FEEDBACK_STUDENT", "STUDENT_START", "STUDENT_FINISH", ], distinct: true, }); const levelArray = levels.rows .map((learning) => ({ NAME_LEVEL: learning.level.NAME_LEVEL, SCORE: learning.SCORE, FEEDBACK_STUDENT: learning.FEEDBACK_STUDENT, STUDENT_START: learning.STUDENT_START, STUDENT_FINISH: learning.STUDENT_FINISH, })) .sort((a, b) => { if (sort === "level") { return a.NAME_LEVEL.localeCompare(b.NAME_LEVEL); } else if (sort === "score") { return b.SCORE - a.SCORE; } else if (sort === "feedback") { return a.FEEDBACK_STUDENT.localeCompare(b.FEEDBACK_STUDENT); } else if (sort === "start") { return new Date(a.STUDENT_START) - new Date(b.STUDENT_START); } else if (sort === "finish") { return new Date(a.STUDENT_FINISH) - new Date(b.STUDENT_FINISH); } return 0; }); // Pagination logic const paginatedResult = levelArray.slice((page - 1) * limit, page * limit); const totalPages = Math.ceil(levels.count / limit); const currentPage = parseInt(page); const result = { ID_MONITORING: monitoring.ID_MONITORING, NAME_SECTION: sectionName, NAME_TOPIC: topicName, NAME_USERS: studentName, NISN: nisn, levels: paginatedResult, currentPage, totalPages, totalItems: levels.count, }; response(200, result, "Success retrieving student progress!", res); } catch (error) { console.error(error); response(500, null, "Error retrieving student progress!", res); } }; export const monitoringFeedback = async (req, res) => { const { id } = req.params; const { feedback } = req.body; if (!req.user) { return response(401, null, "User not authenticated", res); } const { ID } = req.user; if (!ID) { return response(401, null, "Unauthorized: User ID not provided", res); } try { const teacher = await models.Teacher.findOne({ where: { ID: ID }, attributes: ["ID_GURU"], }); if (!teacher) { return response(404, null, "Teacher not found!", res); } const [updatedRows] = await models.Monitoring.update( { ID_GURU: teacher.ID_GURU, FEEDBACK_GURU: feedback, }, { where: { ID_MONITORING: id }, returning: true, } ); if (updatedRows === 0) { return response(404, null, "Monitoring data not found!", res); } const monitoringWithRelations = await models.Monitoring.findOne({ where: { ID_MONITORING: id }, include: [ { model: models.Teacher, as: "monitoringTeacher", attributes: ["ID_GURU"], include: [ { model: models.User, as: "teacherUser", attributes: ["NAME_USERS"], }, ], }, ], }); if (!monitoringWithRelations) { return response(404, null, "Updated monitoring data not found!", res); } const result = { ID_MONITORING: monitoringWithRelations.ID_MONITORING, FEEDBACK_GURU: monitoringWithRelations.FEEDBACK_GURU, ID_GURU: monitoringWithRelations.monitoringTeacher?.ID_GURU, TEACHER_NAME: monitoringWithRelations.monitoringTeacher?.teacherUser?.NAME_USERS, }; response(200, result, "Success updating teacher feedback!", res); } catch (error) { console.error("Error in monitoringFeedback:", error); response(500, null, "Error updating teacher feedback!", res); } }; export const getMonitoringByTopicId = async (req, res) => { const { topicId } = req.params; if (!req.user) { return response(401, null, "User not authenticated", res); } const { ID } = req.user; if (!ID) { return response(401, null, "Unauthorized: User ID not provided", res); } try { const stdLearning = await models.StdLearning.findOne({ where: { ID: ID, }, include: [ { model: models.Level, as: "level", where: { ID_TOPIC: topicId }, attributes: ["ID_LEVEL", "NAME_LEVEL"], include: [ { model: models.Topic, as: "levelTopic", attributes: ["NAME_TOPIC"], }, ], }, ], }); if (!stdLearning) { return response( 404, null, "Student learning data not found for this topic!", res ); } const monitoringData = await models.Monitoring.findOne({ where: { ID_STUDENT_LEARNING: stdLearning.ID_STUDENT_LEARNING, }, include: [ { model: models.Teacher, as: "monitoringTeacher", attributes: ["ID_GURU"], include: [ { model: models.User, as: "teacherUser", attributes: ["NAME_USERS"], }, ], }, ], }); if (!monitoringData) { return response( 404, null, "Monitoring data not found for this learning record!", res ); } const result = { ID_MONITORING: monitoringData.ID_MONITORING, NAME_TOPIC: stdLearning.level?.levelTopic?.NAME_TOPIC, NAME_LEVEL: stdLearning.level?.NAME_LEVEL, TEACHER_NAME: monitoringData.monitoringTeacher?.teacherUser?.NAME_USERS, FEEDBACK_GURU: monitoringData.FEEDBACK_GURU, TIME_MONITORING: monitoringData.TIME_MONITORING, }; response(200, result, "Success retrieving monitoring data!", res); } catch (error) { console.error("Error in getMonitoringByTopicId:", error); response(500, null, "Error retrieving monitoring data!", res); } };