From b15207bc50b635bbd73133e85d8cc5d2bbb06a43 Mon Sep 17 00:00:00 2001 From: Vikrant Kumar Date: Wed, 7 Oct 2026 11:57:06 +0530 Subject: [PATCH] Add a batch-wise total-credits-earned Database report Shows each student's earned credits split into regular, backlog/improvement and swayam, plus the total, same pattern as the other Database reports. --- src/Modules/Database/reports.js | 9 ++ .../Database/reports/CreditsEarnedReport.jsx | 98 +++++++++++++++++++ src/routes/academicRoutes/index.jsx | 1 + 3 files changed, 108 insertions(+) create mode 100644 src/Modules/Database/reports/CreditsEarnedReport.jsx diff --git a/src/Modules/Database/reports.js b/src/Modules/Database/reports.js index 0e7cef8ab..15d56fd09 100644 --- a/src/Modules/Database/reports.js +++ b/src/Modules/Database/reports.js @@ -4,6 +4,7 @@ import StudentCreditTotalsReport from "./reports/StudentCreditTotalsReport"; import CourseRegistrationCountsReport from "./reports/CourseRegistrationCountsReport"; import SwayamRegistrationsReport from "./reports/SwayamRegistrationsReport"; import SemesterRegistrationsReport from "./reports/SemesterRegistrationsReport"; +import CreditsEarnedReport from "./reports/CreditsEarnedReport"; // One entry per report. Adding a report means adding an entry here; the list // page and the report page both read from this. @@ -51,6 +52,14 @@ export const DATABASE_REPORTS = [ filters: "Batch, semester", Component: SemesterRegistrationsReport, }, + { + id: "credits-earned", + title: "Total credits earned", + summary: + "Regular, backlog/improvement and swayam credits each student of a batch has earned so far", + filters: "Batch", + Component: CreditsEarnedReport, + }, ]; export const findReport = (id) => diff --git a/src/Modules/Database/reports/CreditsEarnedReport.jsx b/src/Modules/Database/reports/CreditsEarnedReport.jsx new file mode 100644 index 000000000..4b08bd969 --- /dev/null +++ b/src/Modules/Database/reports/CreditsEarnedReport.jsx @@ -0,0 +1,98 @@ +import { useState } from "react"; +import PropTypes from "prop-types"; +import { Button, Group, Select, Stack, Text } from "@mantine/core"; +import { showNotification } from "@mantine/notifications"; +import { IconSearch } from "@tabler/icons-react"; +import axios from "axios"; +import { databaseCreditsEarnedRoute } from "../../../routes/academicRoutes"; +import ReportTable from "../ReportTable"; + +const COLUMNS = [ + { key: "roll_no", label: "Roll No" }, + { key: "student_name", label: "Student Name" }, + { key: "regular_credits", label: "Regular Credits" }, + { key: "backlog_improvement_credits", label: "Backlog/Improvement Credits" }, + { key: "swayam_credits", label: "Swayam Credits" }, + { key: "total_credits_earned", label: "Total Credits Earned" }, +]; + +const asOptions = (values) => + (values || []).map((v) => ({ value: String(v), label: String(v) })); + +export default function CreditsEarnedReport({ filters }) { + const [batch, setBatch] = useState(null); + const [result, setResult] = useState(null); + const [loading, setLoading] = useState(false); + + const ready = Boolean(batch); + + const run = async () => { + setLoading(true); + try { + const token = localStorage.getItem("authToken"); + const { data } = await axios.get(databaseCreditsEarnedRoute, { + params: { batch }, + headers: token ? { Authorization: `Token ${token}` } : {}, + }); + setResult(data); + if (!data.count) { + showNotification({ + title: "Nothing found", + message: "No graded students match that batch.", + color: "yellow", + }); + } + } catch (error) { + showNotification({ + title: "Error", + message: error.response?.data?.detail || "Could not load the credits.", + color: "red", + }); + } finally { + setLoading(false); + } + }; + + return ( + + +