308 lines
8.7 KiB
TypeScript
308 lines
8.7 KiB
TypeScript
/**
|
|
* Administrator grading API (parity with CI `Views/grading/*.php`).
|
|
* Base: `/api/v1/grading/...` with JWT.
|
|
*/
|
|
import { apiFetch } from './http'
|
|
|
|
const BASE = '/api/v1/grading'
|
|
|
|
export type GradingScoreRow = {
|
|
id?: number
|
|
score?: number | string | null
|
|
comment?: string | null
|
|
}
|
|
|
|
export type GradingSectionScoreStudent = {
|
|
student_id: number
|
|
firstname?: string | null
|
|
lastname?: string | null
|
|
school_id?: string | null
|
|
score?: number | string | null
|
|
scores?: Record<string, number | string | null>
|
|
comments?: Record<
|
|
string,
|
|
{
|
|
comment?: string | null
|
|
comment_review?: string | null
|
|
commented_by?: string | number | null
|
|
reviewed_by?: string | number | null
|
|
}
|
|
>
|
|
}
|
|
|
|
export type GradingScoreFormPayload = {
|
|
scoresLocked?: boolean
|
|
student?: { id?: number; firstname?: string; lastname?: string; school_id?: string | null }
|
|
classSectionId?: number
|
|
class_section_name?: string | null
|
|
scores?: GradingScoreRow[]
|
|
}
|
|
|
|
export type GradingSectionScorePayload = {
|
|
ok?: boolean
|
|
students?: GradingSectionScoreStudent[]
|
|
headers?: number[]
|
|
semester?: string
|
|
school_year?: string
|
|
class_section_id?: number | string
|
|
class_section_name?: string | null
|
|
scores_locked?: boolean
|
|
missing_ok_map?: Record<string, unknown>
|
|
}
|
|
|
|
export type AllDecisionRow = {
|
|
student_id: number
|
|
school_id?: string | null
|
|
firstname?: string | null
|
|
lastname?: string | null
|
|
gender?: string | null
|
|
class_section_id?: number | string | null
|
|
class_section_name?: string | null
|
|
fall_score?: number | string | null
|
|
spring_score?: number | string | null
|
|
year_score?: number | string | null
|
|
decision?: string | null
|
|
source?: string | null
|
|
notes?: string | null
|
|
saved?: boolean
|
|
is_trophy?: boolean
|
|
}
|
|
|
|
export type AllDecisionsPayload = {
|
|
ok?: boolean
|
|
rows?: AllDecisionRow[]
|
|
generated?: boolean
|
|
school_year?: string
|
|
}
|
|
|
|
function q(sp: URLSearchParams): string {
|
|
const s = sp.toString()
|
|
return s ? `?${s}` : ''
|
|
}
|
|
|
|
export async function fetchGradingMain(searchParams: URLSearchParams): Promise<unknown> {
|
|
return apiFetch(`${BASE}/overview${q(searchParams)}`)
|
|
}
|
|
|
|
export async function fetchGradingScoreForm(
|
|
scoreType: string,
|
|
classSectionId: string,
|
|
studentId: string,
|
|
searchParams: URLSearchParams,
|
|
): Promise<GradingScoreFormPayload> {
|
|
return apiFetch(`${BASE}/scores/${encodeURIComponent(scoreType)}/${encodeURIComponent(classSectionId)}/${encodeURIComponent(studentId)}${q(searchParams)}`)
|
|
}
|
|
|
|
function scoreCollectionPath(scoreType: string): string {
|
|
switch (scoreType) {
|
|
case 'homework':
|
|
return '/api/v1/scores/homework'
|
|
case 'quiz':
|
|
return '/api/v1/scores/quizzes'
|
|
case 'project':
|
|
return '/api/v1/scores/projects'
|
|
case 'midterm':
|
|
return '/api/v1/scores/midterm'
|
|
case 'final':
|
|
return '/api/v1/scores/final'
|
|
case 'comments':
|
|
return '/api/v1/scores/comments'
|
|
default:
|
|
throw new Error(`Unsupported score type: ${scoreType}`)
|
|
}
|
|
}
|
|
|
|
export async function fetchGradingSectionScoreTable(
|
|
scoreType: string,
|
|
classSectionId: string,
|
|
searchParams: URLSearchParams,
|
|
): Promise<GradingSectionScorePayload> {
|
|
const next = new URLSearchParams(searchParams)
|
|
next.set('class_section_id', classSectionId)
|
|
return apiFetch(`${scoreCollectionPath(scoreType)}${q(next)}`)
|
|
}
|
|
|
|
export async function postGradingScoreUpdate(
|
|
body: Record<string, unknown>,
|
|
): Promise<unknown> {
|
|
return apiFetch(`${BASE}/scores`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
}
|
|
|
|
export async function postGradingSectionScoreUpdate(
|
|
scoreType: string,
|
|
body: Record<string, unknown>,
|
|
): Promise<unknown> {
|
|
const method = scoreType === 'comments' ? 'PUT' : 'POST'
|
|
return apiFetch(scoreCollectionPath(scoreType), {
|
|
method,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
}
|
|
|
|
export async function fetchBelowSixty(searchParams: URLSearchParams): Promise<unknown> {
|
|
return apiFetch(`${BASE}/below-sixty${q(searchParams)}`)
|
|
}
|
|
|
|
export async function fetchAllDecisions(
|
|
searchParams: URLSearchParams,
|
|
): Promise<AllDecisionsPayload> {
|
|
return apiFetch(`${BASE}/decisions${q(searchParams)}`)
|
|
}
|
|
|
|
export async function postGenerateAllDecisions(body: Record<string, unknown>): Promise<{
|
|
ok?: boolean
|
|
saved_count?: number
|
|
}> {
|
|
return apiFetch(`${BASE}/decisions/generate`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
}
|
|
|
|
export async function fetchBelowSixtyDecisions(
|
|
searchParams: URLSearchParams,
|
|
): Promise<unknown> {
|
|
return apiFetch(`${BASE}/below-sixty/decisions${q(searchParams)}`)
|
|
}
|
|
|
|
export async function postBelowSixtyDecision(body: Record<string, unknown>): Promise<unknown> {
|
|
return apiFetch(`${BASE}/below-sixty/decisions`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
}
|
|
|
|
export async function fetchBelowSixtyDecisionDetails(
|
|
searchParams: URLSearchParams,
|
|
): Promise<unknown> {
|
|
return apiFetch(`${BASE}/below-sixty/decisions/details${q(searchParams)}`)
|
|
}
|
|
|
|
export async function fetchBelowSixtyDecisionEmailEditor(
|
|
searchParams: URLSearchParams,
|
|
): Promise<{
|
|
student_id?: number
|
|
student_name?: string
|
|
school_year?: string
|
|
semester?: string
|
|
decision?: string
|
|
subject?: string
|
|
html?: string
|
|
year_score?: number | string | null
|
|
}> {
|
|
return apiFetch(`${BASE}/below-sixty/decisions/email${q(searchParams)}`)
|
|
}
|
|
|
|
export async function postBelowSixtyDecisionEmail(body: Record<string, unknown>): Promise<unknown> {
|
|
return apiFetch(`${BASE}/below-sixty/decisions/email`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
}
|
|
|
|
export async function fetchBelowSixtyEmailEditor(searchParams: URLSearchParams): Promise<{
|
|
studentId?: number
|
|
studentName?: string
|
|
semester?: string
|
|
schoolYear?: string
|
|
subject?: string
|
|
html?: string
|
|
}> {
|
|
return apiFetch(`${BASE}/below-sixty/email${q(searchParams)}`)
|
|
}
|
|
|
|
export async function postBelowSixtyEmail(body: Record<string, unknown>): Promise<unknown> {
|
|
return apiFetch(`${BASE}/below-sixty/email`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
}
|
|
|
|
export async function postBelowSixtyStatus(body: Record<string, unknown>): Promise<unknown> {
|
|
return apiFetch(`${BASE}/below-sixty/status`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
}
|
|
|
|
export async function fetchHomeworkTracking(
|
|
searchParams: URLSearchParams,
|
|
): Promise<unknown> {
|
|
return apiFetch(`${BASE}/homework-tracking${q(searchParams)}`)
|
|
}
|
|
|
|
export async function fetchParticipation(searchParams: URLSearchParams): Promise<unknown> {
|
|
return apiFetch(`/api/v1/scores/participation${q(searchParams)}`)
|
|
}
|
|
|
|
export async function postParticipation(body: Record<string, unknown>): Promise<unknown> {
|
|
return apiFetch('/api/v1/scores/participation', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
}
|
|
|
|
export async function fetchPlacementIndex(searchParams: URLSearchParams): Promise<unknown> {
|
|
return apiFetch(`${BASE}/placement-index${q(searchParams)}`)
|
|
}
|
|
|
|
export async function postPlacementAll(body: Record<string, unknown>): Promise<unknown> {
|
|
return apiFetch(`${BASE}/placement-all`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
}
|
|
|
|
export async function fetchPlacementSection(searchParams: URLSearchParams): Promise<unknown> {
|
|
return apiFetch(`${BASE}/placement${q(searchParams)}`)
|
|
}
|
|
|
|
export async function postPlacementSection(body: Record<string, unknown>): Promise<unknown> {
|
|
return apiFetch(`${BASE}/placement`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
}
|
|
|
|
export async function fetchPlacementBatch(batchId: string | number): Promise<unknown> {
|
|
return apiFetch(`${BASE}/placement/batch/${batchId}`)
|
|
}
|
|
|
|
export async function postPlacementBatch(
|
|
batchId: string | number,
|
|
body: Record<string, unknown>,
|
|
): Promise<unknown> {
|
|
return apiFetch(`${BASE}/placement/batch/${batchId}`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
}
|
|
|
|
export async function fetchScheduleMeetingForm(
|
|
searchParams: URLSearchParams,
|
|
): Promise<unknown> {
|
|
return apiFetch(`${BASE}/below-sixty/meeting${q(searchParams)}`)
|
|
}
|
|
|
|
export async function postScheduleMeeting(body: Record<string, unknown>): Promise<unknown> {
|
|
return apiFetch(`${BASE}/below-sixty/meeting`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
})
|
|
}
|