update exam and attendance

This commit is contained in:
root
2026-04-26 14:57:41 -04:00
parent 0687d4677f
commit ea495f8382
4 changed files with 912 additions and 181 deletions
File diff suppressed because it is too large Load Diff
+24 -13
View File
@@ -1,8 +1,7 @@
import { useEffect, useMemo, useState, type FormEvent } from 'react'
import { Link, useParams, useSearchParams } from 'react-router-dom'
import { fetchAdministratorCalendarEvents } from '../../api/session'
import { fetchAdministratorCalendarEvents, openProtectedApiFile } from '../../api/session'
import type { ExamDraftRow, SchoolCalendarEventRow } from '../../api/types'
import { apiUrl } from '../../lib/apiOrigin'
import { TeacherShell } from './TeacherShell'
import { useTeacherResource } from './useTeacherResource'
import { postTeacherMultipart } from '../../api/teacherSession'
@@ -114,8 +113,8 @@ type FrontendMeResponse = {
const EXAM_DRAFT_MAX_BYTES = 12 * 1024 * 1024
const EXAM_DRAFT_ALLOWED_EXTENSIONS = ['doc', 'docx']
function teacherExamFileUrl(kind: 'teacher' | 'final', filename?: string | null) {
return filename ? apiUrl(`/api/v1/files/exams/${kind}/${encodeURIComponent(filename)}`) : null
function teacherExamFilePath(kind: 'teacher' | 'final', filename?: string | null) {
return filename ? `/api/v1/files/exams/${kind}/${encodeURIComponent(filename)}` : null
}
/** `teacher/competition_scores/index.php` */
@@ -883,8 +882,8 @@ export function TeacherExamDraftsPage() {
</tr>
) : (
(payload?.drafts ?? []).map((draft) => {
const teacherFile = teacherExamFileUrl('teacher', draft.teacher_file)
const finalFile = teacherExamFileUrl('final', draft.final_pdf_file ?? draft.final_file)
const teacherFile = teacherExamFilePath('teacher', draft.teacher_file)
const finalFile = teacherExamFilePath('final', draft.final_pdf_file ?? draft.final_file)
return (
<tr key={draft.id}>
<td>
@@ -900,16 +899,24 @@ export function TeacherExamDraftsPage() {
<td>
<div className="d-flex flex-column gap-1 small">
{teacherFile ? (
<a href={teacherFile} target="_blank" rel="noreferrer">
<button
type="button"
className="btn btn-link p-0 text-start"
onClick={() => void openProtectedApiFile(teacherFile)}
>
{draft.teacher_filename ?? 'Teacher file'}
</a>
</button>
) : (
<span className="text-muted">No uploaded draft</span>
)}
{finalFile ? (
<a href={finalFile} target="_blank" rel="noreferrer">
<button
type="button"
className="btn btn-link p-0 text-start"
onClick={() => void openProtectedApiFile(finalFile)}
>
{draft.final_filename ?? 'Reviewed final'}
</a>
</button>
) : null}
</div>
</td>
@@ -937,7 +944,7 @@ export function TeacherExamDraftsPage() {
) : (
<div className="row g-3">
{(payload?.legacy_exams ?? []).map((draft) => {
const finalFile = teacherExamFileUrl('final', draft.final_pdf_file ?? draft.final_file)
const finalFile = teacherExamFilePath('final', draft.final_pdf_file ?? draft.final_file)
return (
<div key={draft.id} className="col-12 col-xl-6">
<article className="teacher-calendar-agenda-item h-100">
@@ -951,9 +958,13 @@ export function TeacherExamDraftsPage() {
</p>
<p className="small text-muted mb-2">{draft.description ?? 'No description provided.'}</p>
{finalFile ? (
<a className="btn btn-sm btn-outline-primary" href={finalFile} target="_blank" rel="noreferrer">
<button
type="button"
className="btn btn-sm btn-outline-primary"
onClick={() => void openProtectedApiFile(finalFile)}
>
Download exam
</a>
</button>
) : (
<span className="text-muted small">No file available.</span>
)}