Skip to content

Pull#14

Merged
eshanhasitha merged 23 commits into
eshanfrom
main
Jun 3, 2026
Merged

Pull#14
eshanhasitha merged 23 commits into
eshanfrom
main

Conversation

@eshanhasitha

Copy link
Copy Markdown
Collaborator

No description provided.

eshanhasitha and others added 23 commits June 2, 2026 20:25
PDF Upload with Free OCR
feat: implement admin dashboard with student metrics and management r…
Added a features section to the README.
Updated project description and features section.
Copilot AI review requested due to automatic review settings June 3, 2026 12:56
@netlify

netlify Bot commented Jun 3, 2026

Copy link
Copy Markdown

Deploy Preview for gpacal-cis failed.

Name Link
🔨 Latest commit 1c2a238
🔍 Latest deploy log https://app.netlify.com/projects/gpacal-cis/deploys/6a20246745b1130008f74979

@eshanhasitha eshanhasitha merged commit e21f2b3 into eshan Jun 3, 2026
1 of 5 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces major new functionality for a GPA Calculator Portal: student/admin dashboards, admin-side result ingestion, and schema support for GPA vs non-GPA subjects, along with deployment/docs updates.

Changes:

  • Added student GPA dashboard UI + API (/api/student/gpa) with recommendations and semester/year breakdowns.
  • Added admin dashboard + student browsing/detail views, plus batch-oriented result saving and subject creation updates.
  • Introduced subjects.isGpa to exclude non-GPA subjects from GPA calculations, and added a Markdown-based upload flow for results.

Reviewed changes

Copilot reviewed 34 out of 34 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
README.md New project documentation and setup/deploy guidance.
netlify.toml Netlify build configuration for Next.js.
lib/studentAuth.ts Shared helper to authenticate student requests via JWT cookie.
lib/adminAuth.ts Shared helper to authenticate admin requests via JWT cookie.
lib/schema.ts Adds subjects.isGpa column with default true.
lib/parsePDF.ts More robust OCR text parsing and normalization logic.
lib/parseMD.ts New Markdown/text results parser for admin uploads.
lib/hooks/usePDFOCR.ts Removes client-side PDF OCR hook implementation.
components/ui/accordion.tsx Adds accordion UI component for result grouping displays.
components/admin/AdminSidebar.tsx Adds admin navigation sidebar (mobile + desktop).
app/student/login/page.tsx Redirects first-time students to change-password flow.
app/student/dashboard/page.tsx New student dashboard with GPA, class tier, recommendations, and results table.
app/student/dashboard/loading.tsx Loading skeleton for student dashboard route.
app/student/change-password/page.tsx Enhanced password change UX + first-login flow handling.
app/not-found.tsx Custom 404 page.
app/error.tsx App-level error boundary UI.
app/api/student/gpa/route.ts Student GPA API: aggregates results and computes GPAs/FGPA/classification.
app/api/admin/subjects/route.ts Admin subjects API now supports isGpa.
app/api/admin/students/route.ts Admin list endpoint for computed FGPA/class/pass status with filtering/pagination.
app/api/admin/students/[index]/route.ts Admin student detail endpoint with year/semester drilldown.
app/api/admin/results/save/route.ts Batch-oriented save/upsert of results + student creation; supports non-GPA subjects.
app/api/admin/results/analyze/route.ts Server-side PDF analysis path (Gemini/pdf-parse + parseOCRText fallback).
app/api/admin/dashboard/stats/route.ts Admin dashboard stats endpoint (totals, recent uploads, at-risk count).
app/admin/upload/StepIndicator.tsx Updates wizard step labeling for markdown upload flow.
app/admin/upload/Step1SubjectDetails.tsx Adds GPA vs non-GPA subject type selection.
app/admin/upload/Step2UploadOCR.tsx Reworked step 2 into Markdown/text upload + parsing UX.
app/admin/upload/Step3ReviewEdit.tsx Displays non-GPA status and adjusts grade point display accordingly.
app/admin/upload/page.tsx Wires new upload flow (MD parsing → review/edit → save).
app/admin/students/page.tsx New admin students browsing UI with filtering and pagination.
app/admin/students/loading.tsx Loading skeleton for admin students route.
app/admin/students/[index]/page.tsx New admin student detail UI with FGPA breakdown and record accordion.
app/admin/dashboard/page.tsx New admin dashboard UI (stats + recent uploads).
app/admin/dashboard/loading.tsx Loading skeleton for admin dashboard route.
.env.example Expanded environment variable template (DB/JWT/AI keys).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/parseMD.ts
Comment on lines +69 to +74
// Split by pipe, remove first/last empty elements
const cells = trimmed
.split("|")
.map((c) => c.trim())
.filter((_, i, arr) => i > 0 && i < arr.length); // skip first/last empty from leading/trailing |

Comment on lines +104 to +106
<Icon
className={`h-4.5 w-4.5 flex-shrink-0 transition-colors ${
active
Comment thread README.md
Comment on lines +73 to +77
The database seeder initializes:
- **Default Admin Account**:
- **Username**: `admin`
- **Password**: `admin123`
- **Academic Semesters**: Years 1-4, Semesters 1-2.
Comment on lines 136 to +142
const res = await fetch("/api/auth/student/change-password", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ currentPassword, newPassword }),
body: JSON.stringify({
currentPassword: isFirstLogin ? "123456789" : currentPassword,
newPassword,
}),
Comment on lines +45 to +51
const allResults = await db
.select({
studentIndex: results.studentIndex,
gradePoint: results.gradePoint,
creditPoints: subjects.creditPoints,
yearNumber: semesters.yearNumber,
})
Comment on lines +36 to +46
// ── 1. Fetch matching students (with pagination) ────────────────────
// First get total count for pagination
const countQuery = search
? db
.select({ value: count() })
.from(students)
.where(ilike(students.indexNumber, `%${search}%`))
: db.select({ value: count() }).from(students);

const [totalRow] = await countQuery;

Comment on lines +62 to +70
const allResults = await db
.select({
studentIndex: results.studentIndex,
grade: results.grade,
gradePoint: results.gradePoint,
creditPoints: subjects.creditPoints,
yearNumber: semesters.yearNumber,
semesterId: subjects.semesterId,
})
Comment on lines +97 to +103
if (!studentData.byYear.has(row.yearNumber)) {
studentData.byYear.set(row.yearNumber, []);
}
studentData.byYear.get(row.yearNumber)!.push({
gp: Number(row.gradePoint),
cp: row.creditPoints,
});
Comment on lines +245 to +247
<th className="px-5 py-3 text-left text-xs font-medium text-slate-400 uppercase tracking-wider">
Subjects Done
</th>
Comment on lines +1 to +14
import { NextRequest, NextResponse } from "next/server";
import { verifyToken } from "@/lib/auth";
import { parseOCRText } from "@/lib/parsePDF";
import pdf from "pdf-parse";

// ─── Helper: Verify Admin JWT ───────────────────────────────────────────────

function getAdminFromRequest(request: NextRequest) {
const token = request.cookies.get("auth-token")?.value;
if (!token) return null;
const payload = verifyToken(token);
if (!payload || payload.role !== "admin") return null;
return payload;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants