fix parent pages and teachers and admin
Web Client CI/CD / Lint (ESLint + TypeScript) (push) Successful in 29s
Web Client CI/CD / Build (tsc + Vite) (push) Successful in 23s
Web Client CI/CD / Deploy to shared hosting (push) Successful in 33s

This commit is contained in:
root
2026-07-09 13:56:26 -04:00
parent 4b78aafa65
commit b895c06dc1
15 changed files with 726 additions and 372 deletions
+68 -11
View File
@@ -222,8 +222,7 @@ export async function fetchReportCardCompleteness(params: {
}
/** Build absolute API URL for iframe / window.open (report PDF HTML). */
export function reportCardStudentUrl(
function reportCardStudentPath(
studentId: number | string,
opts: { school_year: string; semester?: string; download?: boolean; report_date?: string },
): string {
@@ -233,10 +232,10 @@ export function reportCardStudentUrl(
if (opts.download) qs.set('download', '1')
if (opts.report_date) qs.set('report_date', opts.report_date)
qs.set('cb', String(Date.now()))
return apiUrl(`/api/v1/reports/report-cards/students/${encodeURIComponent(String(studentId))}?${qs}`)
return `/api/v1/reports/report-cards/students/${encodeURIComponent(String(studentId))}?${qs}`
}
export function reportCardClassUrl(
function reportCardClassPath(
classSectionId: number | string,
opts: { school_year: string; semester?: string; download?: boolean; report_date?: string },
): string {
@@ -246,7 +245,22 @@ export function reportCardClassUrl(
if (opts.download) qs.set('download', '1')
if (opts.report_date) qs.set('report_date', opts.report_date)
qs.set('cb', String(Date.now()))
return apiUrl(`/api/v1/reports/report-cards/classes/${encodeURIComponent(String(classSectionId))}?${qs}`)
return `/api/v1/reports/report-cards/classes/${encodeURIComponent(String(classSectionId))}?${qs}`
}
/** Build absolute API URL for iframe / window.open (report PDF HTML). */
export function reportCardStudentUrl(
studentId: number | string,
opts: { school_year: string; semester?: string; download?: boolean; report_date?: string },
): string {
return apiUrl(reportCardStudentPath(studentId, opts))
}
export function reportCardClassUrl(
classSectionId: number | string,
opts: { school_year: string; semester?: string; download?: boolean; report_date?: string },
): string {
return apiUrl(reportCardClassPath(classSectionId, opts))
}
/** HTML document for iframe preview (Bearer auth; unlike raw iframe src). */
@@ -288,15 +302,58 @@ export async function fetchReportCardClassHtml(
return res.text()
}
/** Opens PDF download in new tab (authenticated GET). */
export async function openReportCardDownload(url: string): Promise<void> {
async function fetchReportCardPdf(path: string): Promise<Blob> {
const headers = new Headers({ Accept: 'application/pdf,*/*' })
const token = getStoredToken()
if (!token) {
throw new ApiHttpError('Your session has expired. Please sign in again.', 401, null)
}
if (token) headers.set('Authorization', `Bearer ${token}`)
applyStoredSchoolYearHeaders(headers)
const res = await fetch(url, { headers })
if (!res.ok) throw new ApiHttpError(`HTTP ${res.status}`, res.status, null)
const res = await fetch(apiUrl(path), { headers })
if (!res.ok) {
const errBody: unknown = await res.json().catch(() => null)
const msg =
typeof errBody === 'object' && errBody !== null && 'message' in errBody
? String((errBody as { message?: unknown }).message ?? '')
: ''
throw new ApiHttpError(msg || `HTTP ${res.status}`, res.status, errBody)
}
const raw = await res.blob()
const blob = new Blob([await raw.arrayBuffer()], { type: 'application/pdf' })
window.open(URL.createObjectURL(blob), '_blank', 'noopener')
return new Blob([await raw.arrayBuffer()], { type: 'application/pdf' })
}
function openBlob(blob: Blob): void {
const objectUrl = URL.createObjectURL(blob)
window.open(objectUrl, '_blank', 'noopener')
window.setTimeout(() => URL.revokeObjectURL(objectUrl), 60_000)
}
/** Opens PDF download in new tab (authenticated GET). */
export async function openReportCardStudentDownload(
studentId: number | string,
opts: { school_year: string; semester?: string; report_date?: string },
): Promise<void> {
openBlob(
await fetchReportCardPdf(
reportCardStudentPath(studentId, {
...opts,
download: true,
}),
),
)
}
export async function openReportCardClassDownload(
classSectionId: number | string,
opts: { school_year: string; semester?: string; report_date?: string },
): Promise<void> {
openBlob(
await fetchReportCardPdf(
reportCardClassPath(classSectionId, {
...opts,
download: true,
}),
),
)
}
+1 -1
View File
@@ -448,7 +448,7 @@ export async function fetchParentStatement(params: {
if (params.parentId != null) query.set('parent_id', String(params.parentId))
const response = await apiFetch<ApiParentStatementResponse>(
`/api/v1/parent/statements${query.toString() ? `?${query}` : ''}`,
`/api/v1/parents/statements${query.toString() ? `?${query}` : ''}`,
)
if (!response.data) {
+8
View File
@@ -1974,6 +1974,8 @@ export async function fetchClassProgressGroups(params?: {
weekStart?: string | null
weekEnd?: string | null
subject?: string | null
schoolYear?: string | null
semester?: string | null
page?: number
perPage?: number
}): Promise<ClassProgressGroupsResponse> {
@@ -1984,6 +1986,8 @@ export async function fetchClassProgressGroups(params?: {
if (params?.weekStart) query.set('week_start', params.weekStart)
if (params?.weekEnd) query.set('week_end', params.weekEnd)
if (params?.subject) query.set('subject', params.subject)
if (params?.schoolYear) query.set('school_year', params.schoolYear)
if (params?.semester) query.set('semester', params.semester)
if (params?.page) query.set('page', String(params.page))
if (params?.perPage) query.set('per_page', String(params.perPage))
return apiFetch<ClassProgressGroupsResponse>(`/api/v1/class-progress?${query.toString()}`)
@@ -1996,10 +2000,14 @@ export async function fetchClassProgressDetail(id: number): Promise<ClassProgres
export async function fetchClassProgressMeta(params?: {
classId?: number | null
sundayCount?: number | null
schoolYear?: string | null
semester?: string | null
}): Promise<ClassProgressMetaResponse> {
const query = new URLSearchParams()
if (params?.classId) query.set('class_id', String(params.classId))
if (params?.sundayCount) query.set('sunday_count', String(params.sundayCount))
if (params?.schoolYear) query.set('school_year', params.schoolYear)
if (params?.semester) query.set('semester', params.semester)
const qs = query.size > 0 ? `?${query.toString()}` : ''
return apiFetch<ClassProgressMetaResponse>(`/api/v1/class-progress/meta${qs}`)
}
+14
View File
@@ -349,9 +349,23 @@ export type ParentProfileResponse = {
export type ParentInvoiceRow = {
id: number
invoice_number?: string | null
total_amount?: number
paid_amount?: number
balance?: number
status?: string | null
due_date?: string | null
last_paid_amount?: number
last_payment_date?: string | null
payments?: Array<{
id: number
invoice_id?: number
paid_amount?: number
balance?: number
payment_method?: string | null
payment_date?: string | null
transaction_id?: string | null
status?: string | null
}>
}
export type ParentInvoicesResponse = {