Skip to content

pull#3

Merged
indubrolk merged 3 commits into
indufrom
main
Jun 2, 2026
Merged

pull#3
indubrolk merged 3 commits into
indufrom
main

Conversation

@indubrolk

Copy link
Copy Markdown
Owner

No description provided.

Copilot AI review requested due to automatic review settings June 2, 2026 15:03

@indubrolk indubrolk left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

done

@indubrolk indubrolk merged commit 77cba60 into indu Jun 2, 2026
1 check 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 an admin “Upload Result Sheet” flow that OCRs scanned PDF result sheets in the browser, parses out student index/grade pairs, and persists subjects/results via new admin API routes. It expands the UI component set used by the new upload wizard and adds PDF/OCR dependencies and Next.js bundling configuration to support pdfjs-dist and tesseract.js.

Changes:

  • Add client-side PDF rendering + OCR hook (pdfjs-dist + tesseract.js) and OCR-text parser for extracting subject/semester metadata and index+grade pairs.
  • Add admin upload wizard (multi-step UI) to review/edit extracted rows and submit to new admin API endpoints.
  • Add new admin API routes for subject lookup/creation and bulk result saving (plus pdf upload logging).

Reviewed changes

Copilot reviewed 18 out of 21 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
package.json Adds pdfjs-dist and tesseract.js dependencies needed for client-side PDF OCR.
package-lock.json Locks transitive dependencies introduced by pdfjs-dist/tesseract.js.
next.config.js Adds webpack customization intended to avoid bundling/using canvas on the server.
lib/parsePDF.ts Implements OCR text parsing to extract subject/semester header info and index+grade pairs.
lib/hooks/usePDFOCR.ts Implements client-side PDF rendering + OCR pipeline and progress reporting.
components/ui/tooltip.tsx Adds a tooltip component used in the review/edit step.
components/ui/table.tsx Adds table primitives for rendering the editable results table.
components/ui/select.tsx Adds a styled <select> used in the upload wizard.
components/ui/progress.tsx Adds a progress bar used during OCR processing.
components/ui/badge.tsx Adds badge styling used for step summaries and labels.
components/ui/alert.tsx Adds alert variants used for OCR success/warning/error messaging.
components/ui/alert-dialog.tsx Adds confirmation dialog used before saving results.
app/api/admin/subjects/route.ts Adds admin endpoints to list subjects and create a subject+semester if missing.
app/api/admin/results/save/route.ts Adds admin endpoint to save OCR’d results and create missing student accounts.
app/admin/upload/StepIndicator.tsx Adds step indicator UI for the upload wizard.
app/admin/upload/Step4Success.tsx Adds success screen showing saved/created/skipped counts.
app/admin/upload/Step3ReviewEdit.tsx Adds editable review table and grade distribution UI prior to saving.
app/admin/upload/Step2UploadOCR.tsx Adds PDF drop-zone and OCR progress UI and triggers step advancement.
app/admin/upload/Step1SubjectDetails.tsx Adds subject detail entry with subject-code lookup/autofill behavior.
app/admin/upload/page.tsx Wires the full multi-step upload flow together and calls the new APIs.

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

Comment on lines +46 to +49
// Auto-advance when done
if (result && selectedFile && progress.status === "done") {
setTimeout(() => onDone(selectedFile), 800);
}
@@ -0,0 +1,169 @@
"use client";

import { useCallback, useRef, useState } from "react";
import { Select } from "@/components/ui/select";
import { Button } from "@/components/ui/button";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { useEffect, useState, useCallback } from "react";
Comment on lines +52 to +64
setFormData({
...formData,
subjectCode: code,
subjectName: match.subjectName,
creditPoints: match.creditPoints,
yearNumber: match.yearNumber,
semesterNumber: match.semesterNumber,
subjectId: match.id,
});
} else {
setCodeStatus("new");
setFormData({ ...formData, subjectCode: code, subjectId: null });
}
} finally {
setChecking(false);
}
}, [formData.subjectCode]);
Comment on lines +70 to +98
// ── 1. Upsert student ───────────────────────────────────────────
// Insert student with default password, skip if already exists
const existingStudents = await db
.select()
.from(students)
.where(eq(students.indexNumber, indexNumber))
.limit(1);

if (existingStudents.length === 0) {
await db.insert(students).values({
indexNumber,
passwordHash: defaultPasswordHash,
isFirstLogin: true,
});
created++;
}

// ── 2. Check for existing result for this student + subject ─────
const existingResults = await db
.select()
.from(results)
.where(
and(
eq(results.studentIndex, indexNumber),
eq(results.subjectId, subjectId)
)
)
.limit(1);

Comment on lines +104 to +122
// Find semester row by yearNumber + semesterNumber, create if missing
let semesterRows = await db
.select()
.from(semesters)
.where(
and(
eq(semesters.yearNumber, yearNumber),
eq(semesters.semesterNumber, semesterNumber)
)
)
.limit(1);

if (semesterRows.length === 0) {
const label = `Year ${yearNumber} - Semester ${semesterNumber}`;
semesterRows = await db
.insert(semesters)
.values({ yearNumber, semesterNumber, label })
.returning();
}
Comment thread lib/hooks/usePDFOCR.ts
Comment on lines +110 to +116
// Dynamic import Tesseract.js
const Tesseract = await import("tesseract.js");
const worker = await Tesseract.createWorker("eng");
const { data } = await worker.recognize(canvas);
allText += data.text + "\n";
await worker.terminate();

Comment thread lib/hooks/usePDFOCR.ts
Comment on lines +68 to +70
pdfjsLib.GlobalWorkerOptions.workerSrc =
"https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js";

Comment on lines +21 to +23
export function Step2UploadOCR({
processFile, progress, result, error, reset, subjectCode, onDone,
}: Step2Props) {
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.

3 participants