From efbb2ec628525810b718eb417362647b9c3095a8 Mon Sep 17 00:00:00 2001 From: Vikrant Kumar Date: Sun, 27 Sep 2026 22:30:32 +0530 Subject: [PATCH 1/3] Rename course registration copies and add mobile number field --- src/Modules/Academic/RegisteredCourses.jsx | 30 ++++++++-- .../Academic/courseRegistrationReceipt.js | 58 ++++++++++++++++--- 2 files changed, 76 insertions(+), 12 deletions(-) diff --git a/src/Modules/Academic/RegisteredCourses.jsx b/src/Modules/Academic/RegisteredCourses.jsx index 3325a2515..a1d4075c9 100644 --- a/src/Modules/Academic/RegisteredCourses.jsx +++ b/src/Modules/Academic/RegisteredCourses.jsx @@ -416,7 +416,7 @@ export default function RegisteredCourses() { paddingBottom: "5px", }} > - STUDENT COPY + Course Confirmation Form (Student Copy)

- Additional notes: + Additional notes:{" "} + For Backlog/Improvement course
Student's Signature
+
+ Mobile Number: +
- ACADEMIC COPY + Course Confirmation Form (Academic Copy)

- Additional notes: + Additional notes:{" "} + For Backlog/Improvement course
Student's Signature
+
+ Mobile Number: +
Date: Sun, 27 Sep 2026 22:30:48 +0530 Subject: [PATCH 2/3] Congratulate a student who has met the degree credit requirement --- .../Dashboard/StudentCreditSummary.jsx | 23 ++++++++- .../Dashboard/StudentCreditSummary.test.jsx | 50 +++++++++++++++++++ src/lib/credits.js | 4 ++ src/lib/credits.test.js | 18 +++++++ 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/src/Modules/Dashboard/StudentCreditSummary.jsx b/src/Modules/Dashboard/StudentCreditSummary.jsx index d5c2608fb..ad36b107b 100644 --- a/src/Modules/Dashboard/StudentCreditSummary.jsx +++ b/src/Modules/Dashboard/StudentCreditSummary.jsx @@ -28,6 +28,7 @@ import { SWAYAM_CREDIT_CAP, computeCreditSummary, fmtCredits, + hasCompletedDegree, remainingCreditRequirement, swayamAboveCap, } from "../../lib/credits"; @@ -274,7 +275,27 @@ export default function StudentCreditSummary() { - {isUg && ( + {isUg && hasCompletedDegree(totals) && ( + + + + Congratulations, you have completed your degree successfully + + + All {DEGREE_CREDIT_REQUIREMENT} credits required for the degree + have been earned. + + + + )} + + {isUg && !hasCompletedDegree(totals) && ( { ); }); + it("congratulates a UG student who has met the requirement, and drops the sum", async () => { + axios.get.mockResolvedValue({ + data: { + semesters: [ + { + label: "Semester 1", + courses: [ + { code: "CS1010", credits: 148, grade: "A", remark: "Regular" }, + ], + }, + ], + programme_category: "UG", + }, + }); + renderPanel(); + + await waitFor(() => + expect(screen.getByText("Credits Details")).toBeInTheDocument(), + ); + + expect( + screen.getByText( + "Congratulations, you have completed your degree successfully", + ), + ).toBeInTheDocument(); + expect( + screen.queryByText("Remaining Credits requirement for degree"), + ).not.toBeInTheDocument(); + }); + + it("still shows the remaining requirement while credits are outstanding", async () => { + axios.get.mockResolvedValue({ + data: { semesters: SEMESTERS, programme_category: "UG" }, + }); + renderPanel(); + + await waitFor(() => + expect(screen.getByText("Credits Details")).toBeInTheDocument(), + ); + + expect( + screen.getByText("Remaining Credits requirement for degree"), + ).toBeInTheDocument(); + expect( + screen.queryByText( + "Congratulations, you have completed your degree successfully", + ), + ).not.toBeInTheDocument(); + }); + it("totals the credits and states the degree requirement", async () => { axios.get.mockResolvedValue({ data: { semesters: SEMESTERS, programme_category: "UG" }, diff --git a/src/lib/credits.js b/src/lib/credits.js index 20bae2d02..9f1f1eb20 100644 --- a/src/lib/credits.js +++ b/src/lib/credits.js @@ -98,3 +98,7 @@ export const creditsTowardsDegree = (totals) => export function remainingCreditRequirement(totals) { return DEGREE_CREDIT_REQUIREMENT - creditsTowardsDegree(totals); } + +// Nothing left to earn, so a student carrying surplus credits counts as done. +export const hasCompletedDegree = (totals) => + remainingCreditRequirement(totals) <= 0; diff --git a/src/lib/credits.test.js b/src/lib/credits.test.js index 7209c44e4..beb09afd0 100644 --- a/src/lib/credits.test.js +++ b/src/lib/credits.test.js @@ -3,6 +3,7 @@ import { describe, expect, it } from "vitest"; import { computeCreditSummary, fmtCredits, + hasCompletedDegree, remainingCreditRequirement, } from "./credits"; @@ -251,3 +252,20 @@ describe("remainingCreditRequirement", () => { expect(remainingCreditRequirement({ earned: 151, swayam: 5 })).toBe(-3); }); }); + +describe("hasCompletedDegree", () => { + it("is false while credits are still outstanding", () => { + expect(hasCompletedDegree({ earned: 122, swayam: 6 })).toBe(false); + expect(hasCompletedDegree({ earned: 147, swayam: 0 })).toBe(false); + }); + + it("is true on exactly the requirement, and on a surplus", () => { + expect(hasCompletedDegree({ earned: 148, swayam: 0 })).toBe(true); + expect(hasCompletedDegree({ earned: 151, swayam: 5 })).toBe(true); + }); + + it("does not count swayam credits above the cap towards completion", () => { + // 150 earned, but 4 of the 10 swayam credits do not count: 146 < 148. + expect(hasCompletedDegree({ earned: 150, swayam: 10 })).toBe(false); + }); +}); From 657b68132af4415ac455de8665c422cf6e854427 Mon Sep 17 00:00:00 2001 From: Vikrant Kumar Date: Sun, 27 Sep 2026 22:30:48 +0530 Subject: [PATCH 3/3] Show degree standing, academic year and last graded semester on Grade Validation --- src/Modules/Examination/GradeValidation.jsx | 36 +++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/Modules/Examination/GradeValidation.jsx b/src/Modules/Examination/GradeValidation.jsx index 66d6b98f1..b5c139c59 100644 --- a/src/Modules/Examination/GradeValidation.jsx +++ b/src/Modules/Examination/GradeValidation.jsx @@ -80,6 +80,25 @@ function buildCreditsDetailsHTML(semesters) { } function buildValidationHTML(studentInfo, semesters) { + // Decided by the server, which owns what this record says; blank for the + // programmes the 148-credit rule does not describe. + const standingText = studentInfo.standing_text || ""; + const completionRow = standingText + ? ` + + ${esc(standingText)} + ` + : ""; + + const lastGraded = studentInfo.last_graded_semester || ""; + const lastGradedRow = lastGraded + ? ` + + Last Graded Semester + ${esc(lastGraded)} + ` + : ""; + const semesterBlocks = semesters .map((sem) => { const isReg = sem.is_registered_only === true; @@ -110,7 +129,10 @@ function buildValidationHTML(studentInfo, semesters) { return `
-
${esc(sem.label)}
+
+ ${esc(sem.label)} + ${esc(sem.academic_year || "")} +
@@ -166,6 +188,16 @@ function buildValidationHTML(studentInfo, semesters) { background: #dce7f3; border: 1pt solid #000; border-bottom: none; + display: flex; + justify-content: space-between; + align-items: baseline; + } + .sem-year { font-weight: bold; } + + .standing { + text-align: center; + font-weight: bold; + color: #c00000; } .course-table { @@ -264,7 +296,7 @@ function buildValidationHTML(studentInfo, semesters) { - + ${lastGradedRow}${completionRow}
${esc(studentInfo.name)} Discipline ${esc(studentInfo.discipline)}
${semesterBlocks}