add school year and security fix
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { apiUrl } from '../lib/apiOrigin'
|
||||
import { ApiHttpError, apiFetch, getStoredToken } from './http'
|
||||
import { ApiHttpError, apiFetch, applyStoredSchoolYearHeaders, getStoredToken } from './http'
|
||||
import type { ApiEnvelope } from './types'
|
||||
|
||||
export type CertificateDecisionRow = {
|
||||
@@ -74,6 +74,7 @@ function authHeaders(accept: string) {
|
||||
const headers = new Headers({ Accept: accept })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
return headers
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { apiUrl } from '../lib/apiOrigin'
|
||||
import { selectedSchoolYearHeaders } from '../lib/schoolYearSelection'
|
||||
|
||||
const TOKEN_KEY = 'alrahma_api_token'
|
||||
|
||||
@@ -30,6 +31,14 @@ export function decodeJwtPayload<T = unknown>(token: string): T | null {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function applyStoredSchoolYearHeaders(headers: Headers): Headers {
|
||||
for (const [key, value] of Object.entries(selectedSchoolYearHeaders())) {
|
||||
if (!headers.has(key)) headers.set(key, value)
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
export class ApiHttpError extends Error {
|
||||
readonly status: number
|
||||
readonly body: unknown
|
||||
@@ -60,6 +69,10 @@ export async function apiFetch<T>(
|
||||
headers.set('Authorization', `Bearer ${token}`)
|
||||
}
|
||||
|
||||
if (attachAuth && token) {
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
}
|
||||
|
||||
const url = apiUrl(path)
|
||||
|
||||
let res: Response
|
||||
|
||||
+6
-7
@@ -2,7 +2,7 @@
|
||||
* Administrator invoice management & PDF (parity with CI `invoice_payment/*`).
|
||||
*/
|
||||
import { apiUrl } from '../lib/apiOrigin'
|
||||
import { apiFetch, getStoredToken } from './http'
|
||||
import { apiFetch, applyStoredSchoolYearHeaders, getStoredToken } from './http'
|
||||
|
||||
const BASE = '/api/v1/finance/invoices'
|
||||
|
||||
@@ -50,12 +50,11 @@ export async function fetchInvoicePreview(invoiceId: string | number): Promise<u
|
||||
/** Binary PDF with JWT (for tabs that cannot send Authorization). */
|
||||
export async function fetchInvoicePdfBlob(invoiceId: string | number): Promise<Blob> {
|
||||
const token = getStoredToken()
|
||||
const res = await fetch(apiUrl(`${BASE}/${invoiceId}/pdf`), {
|
||||
headers: {
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
Accept: 'application/pdf',
|
||||
},
|
||||
})
|
||||
const headers = new Headers({ Accept: 'application/pdf' })
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
|
||||
const res = await fetch(apiUrl(`${BASE}/${invoiceId}/pdf`), { headers })
|
||||
if (!res.ok) {
|
||||
const text = await res.text().catch(() => '')
|
||||
throw new Error(text || `PDF HTTP ${res.status}`)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Paths mirror Laravel `/api/v1/administrator/...` conventions expected by the SPA.
|
||||
*/
|
||||
import { apiUrl } from '../lib/apiOrigin'
|
||||
import { ApiHttpError, apiFetch, getStoredToken } from './http'
|
||||
import { ApiHttpError, apiFetch, applyStoredSchoolYearHeaders, getStoredToken } from './http'
|
||||
|
||||
export type AdminNotificationRow = {
|
||||
id?: number
|
||||
@@ -56,6 +56,7 @@ async function postMultipart<T>(path: string, formData: FormData): Promise<T> {
|
||||
const headers = new Headers({ Accept: 'application/json' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl(path), { method: 'POST', headers, body: formData })
|
||||
const body: unknown = await res.json().catch(() => null)
|
||||
if (!res.ok) {
|
||||
@@ -136,6 +137,7 @@ export async function fetchAuthenticatedBlobUrl(apiPath: string): Promise<string
|
||||
const headers = new Headers({ Accept: '*/*' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl(apiPath), { headers })
|
||||
if (!res.ok) throw new ApiHttpError(`HTTP ${res.status}`, res.status, null)
|
||||
const blob = await res.blob()
|
||||
@@ -335,6 +337,7 @@ export async function downloadFinancialReportCsv(params: {
|
||||
const headers = new Headers()
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl(path), { headers })
|
||||
if (!res.ok) throw new ApiHttpError(`HTTP ${res.status}`, res.status, null)
|
||||
const blob = await res.blob()
|
||||
@@ -408,6 +411,7 @@ export async function downloadFinancialSummaryPdf(params: { school_year?: string
|
||||
const headers = new Headers()
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl(path), { headers })
|
||||
if (!res.ok) throw new ApiHttpError(`HTTP ${res.status}`, res.status, null)
|
||||
const raw = await res.blob()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Teacher / admin print copy requests (legacy CI: print-requests/*).
|
||||
*/
|
||||
import { apiUrl } from '../lib/apiOrigin'
|
||||
import { ApiHttpError, apiFetch, getStoredToken } from './http'
|
||||
import { ApiHttpError, apiFetch, applyStoredSchoolYearHeaders, getStoredToken } from './http'
|
||||
|
||||
export type PrintRequestRow = Record<string, unknown>
|
||||
|
||||
@@ -23,6 +23,7 @@ async function multipartRequest<T>(path: string, formData: FormData, method = 'P
|
||||
const headers = new Headers({ Accept: 'application/json' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl(path), { method, headers, body: formData })
|
||||
const body: unknown = await res.json().catch(() => null)
|
||||
if (!res.ok) {
|
||||
@@ -83,6 +84,7 @@ export async function openPrintRequestFile(requestId: number | string): Promise<
|
||||
const token = getStoredToken()
|
||||
const headers = new Headers({ Accept: '*/*' })
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl(printRequestFileUrl(requestId)), { headers })
|
||||
if (!res.ok) throw new ApiHttpError(`HTTP ${res.status}`, res.status, null)
|
||||
const blob = await res.blob()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Stickers, badges, report cards (legacy CI printables_reports/*).
|
||||
*/
|
||||
import { apiUrl } from '../lib/apiOrigin'
|
||||
import { ApiHttpError, apiFetch, getStoredToken } from './http'
|
||||
import { ApiHttpError, apiFetch, applyStoredSchoolYearHeaders, getStoredToken } from './http'
|
||||
|
||||
export type ClassOption = { class_section_id?: number; id?: number; class_section_name?: string }
|
||||
|
||||
@@ -40,6 +40,7 @@ export async function postStickerGenerate(formData: FormData): Promise<Blob> {
|
||||
const headers = new Headers({ Accept: 'application/pdf,*/*' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl('/api/v1/administrator/printables/stickers/generate'), {
|
||||
method: 'POST',
|
||||
headers,
|
||||
@@ -61,6 +62,7 @@ export async function postBadgeGenerate(formData: FormData): Promise<Blob> {
|
||||
const headers = new Headers({ Accept: 'application/pdf,*/*' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl('/api/v1/badges/pdf'), {
|
||||
method: 'POST',
|
||||
headers,
|
||||
@@ -242,6 +244,7 @@ export async function fetchReportCardStudentHtml(
|
||||
const headers = new Headers({ Accept: 'text/html' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const path = `/api/v1/reports/report-cards/students/${encodeURIComponent(String(studentId))}?${qs}`
|
||||
const res = await fetch(apiUrl(path), { headers })
|
||||
if (!res.ok) throw new ApiHttpError(`HTTP ${res.status}`, res.status, null)
|
||||
@@ -260,6 +263,7 @@ export async function fetchReportCardClassHtml(
|
||||
const headers = new Headers({ Accept: 'text/html' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const path = `/api/v1/reports/report-cards/classes/${encodeURIComponent(String(classSectionId))}?${qs}`
|
||||
const res = await fetch(apiUrl(path), { headers })
|
||||
if (!res.ok) throw new ApiHttpError(`HTTP ${res.status}`, res.status, null)
|
||||
@@ -271,6 +275,7 @@ export async function openReportCardDownload(url: string): Promise<void> {
|
||||
const headers = new Headers({ Accept: 'application/pdf,*/*' })
|
||||
const token = getStoredToken()
|
||||
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 raw = await res.blob()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Backend is expected under `/api/v1/administrator/reimbursements`.
|
||||
*/
|
||||
import { apiUrl } from '../lib/apiOrigin'
|
||||
import { ApiHttpError, apiFetch, getStoredToken } from './http'
|
||||
import { ApiHttpError, apiFetch, applyStoredSchoolYearHeaders, getStoredToken } from './http'
|
||||
|
||||
const BASE = '/api/v1/administrator/reimbursements'
|
||||
|
||||
@@ -58,6 +58,7 @@ export async function downloadReimbursementsExport(params?: {
|
||||
const headers = new Headers({ Accept: 'text/csv,*/*' })
|
||||
const token = getStoredToken()
|
||||
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 blob = await res.blob()
|
||||
@@ -70,6 +71,7 @@ export async function downloadBatchCsv(batchId: number | string): Promise<void>
|
||||
const headers = new Headers({ Accept: 'text/csv,*/*' })
|
||||
const token = getStoredToken()
|
||||
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 blob = await res.blob()
|
||||
@@ -80,6 +82,7 @@ export async function postBatchEmail(formData: FormData): Promise<{ success?: bo
|
||||
const headers = new Headers({ Accept: 'application/json' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl(`${BASE}/batch/send`), { method: 'POST', headers, body: formData })
|
||||
const body: unknown = await res.json().catch(() => null)
|
||||
if (!res.ok) {
|
||||
@@ -118,6 +121,7 @@ async function postFormExpectJson(path: string, form: FormData): Promise<{ succe
|
||||
const headers = new Headers({ Accept: 'application/json', 'X-Requested-With': 'XMLHttpRequest' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl(path), { method: 'POST', headers, body: form })
|
||||
const body: unknown = await res.json().catch(() => ({}))
|
||||
const data = body as Record<string, unknown>
|
||||
@@ -165,6 +169,7 @@ async function postMultipart(path: string, formData: FormData): Promise<{ ok?: b
|
||||
const headers = new Headers({ Accept: 'application/json' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl(path), { method: 'POST', headers, body: formData })
|
||||
const body: unknown = await res.json().catch(() => null)
|
||||
if (!res.ok) {
|
||||
|
||||
@@ -9,6 +9,7 @@ export type SchoolYearRecord = {
|
||||
end_date: string
|
||||
status: SchoolYearStatus
|
||||
is_current: boolean
|
||||
isCurrent?: boolean
|
||||
closed_at?: string | null
|
||||
closed_by?: number | null
|
||||
}
|
||||
@@ -95,6 +96,65 @@ export type SchoolYearCloseResult = {
|
||||
balance_counts?: Record<string, number>
|
||||
}
|
||||
|
||||
export type SchoolYearClosingReport = {
|
||||
old_school_year?: SchoolYearRecord | null
|
||||
new_school_year?: SchoolYearRecord | null
|
||||
closed_by?: string | number | null
|
||||
closed_at?: string | null
|
||||
audit_reference?: string | null
|
||||
totals?: {
|
||||
students_promoted?: number
|
||||
students_repeated?: number
|
||||
students_graduated?: number
|
||||
students_transferred?: number
|
||||
students_withdrawn?: number
|
||||
parents_with_unpaid_balances?: number
|
||||
total_unpaid_balance_transferred?: number
|
||||
parents_with_credit_balances?: number
|
||||
total_credit_transferred?: number
|
||||
}
|
||||
warnings?: string[]
|
||||
}
|
||||
|
||||
export type SchoolYearBalanceTransferReportRow = {
|
||||
parent_id: number
|
||||
parent_name?: string | null
|
||||
old_school_year?: string | null
|
||||
new_school_year?: string | null
|
||||
source_invoice_ids?: Array<number | string>
|
||||
old_unpaid_amount?: number
|
||||
new_old_balance_invoice_id?: number | string | null
|
||||
transfer_status?: string | null
|
||||
transfer_date?: string | null
|
||||
created_by?: string | number | null
|
||||
}
|
||||
|
||||
export type SchoolYearBalanceTransferReport = {
|
||||
school_year?: SchoolYearRecord | null
|
||||
rows: SchoolYearBalanceTransferReportRow[]
|
||||
summary?: {
|
||||
parent_count?: number
|
||||
total_transferred?: number
|
||||
total_credit?: number
|
||||
}
|
||||
}
|
||||
|
||||
export type ParentStatementLine = {
|
||||
label: string
|
||||
amount: number
|
||||
source_school_year?: string | null
|
||||
invoice_id?: number | string | null
|
||||
}
|
||||
|
||||
export type ParentStatement = {
|
||||
parent_id?: number | null
|
||||
parent_name?: string | null
|
||||
school_year?: SchoolYearRecord | string | null
|
||||
lines: ParentStatementLine[]
|
||||
opening_balance?: number
|
||||
current_balance?: number
|
||||
}
|
||||
|
||||
export type SaveSchoolYearPayload = {
|
||||
name: string
|
||||
start_date: string
|
||||
@@ -103,6 +163,15 @@ export type SaveSchoolYearPayload = {
|
||||
|
||||
export type CloseSchoolYearPayload = {
|
||||
new_school_year: SaveSchoolYearPayload
|
||||
promotion_rules?: {
|
||||
default_action?: string
|
||||
exceptions?: Array<{
|
||||
student_id: number
|
||||
action: string
|
||||
target_grade_id?: number | null
|
||||
target_class_section_id?: number | null
|
||||
}>
|
||||
}
|
||||
transfer_unpaid_balances?: boolean
|
||||
confirmation?: string
|
||||
}
|
||||
@@ -147,6 +216,21 @@ type ApiCloseResponse = {
|
||||
data?: SchoolYearCloseResult
|
||||
}
|
||||
|
||||
type ApiClosingReportResponse = {
|
||||
ok?: boolean
|
||||
data?: SchoolYearClosingReport
|
||||
}
|
||||
|
||||
type ApiBalanceTransferReportResponse = {
|
||||
ok?: boolean
|
||||
data?: SchoolYearBalanceTransferReport
|
||||
}
|
||||
|
||||
type ApiParentStatementResponse = {
|
||||
ok?: boolean
|
||||
data?: ParentStatement
|
||||
}
|
||||
|
||||
export async function fetchSchoolYears(): Promise<SchoolYearRecord[]> {
|
||||
const response = await apiFetch<ApiListResponse>('/api/v1/school-years')
|
||||
return response.data ?? []
|
||||
@@ -292,3 +376,51 @@ export async function fetchSchoolYearPromotionPreview(
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
|
||||
export async function fetchSchoolYearClosingReport(
|
||||
schoolYearId: number,
|
||||
): Promise<SchoolYearClosingReport> {
|
||||
const response = await apiFetch<ApiClosingReportResponse>(
|
||||
`/api/v1/school-years/${schoolYearId}/reports/closing`,
|
||||
)
|
||||
|
||||
if (!response.data) {
|
||||
throw new Error('School year closing report returned no payload.')
|
||||
}
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
export async function fetchSchoolYearBalanceTransferReport(
|
||||
schoolYearId: number,
|
||||
): Promise<SchoolYearBalanceTransferReport> {
|
||||
const response = await apiFetch<ApiBalanceTransferReportResponse>(
|
||||
`/api/v1/school-years/${schoolYearId}/parent-balances`,
|
||||
)
|
||||
|
||||
if (!response.data) {
|
||||
throw new Error('School year balance transfer report returned no payload.')
|
||||
}
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
export async function fetchParentStatement(params: {
|
||||
schoolYearId?: number | null
|
||||
parentId?: number | null
|
||||
}): Promise<ParentStatement> {
|
||||
const query = new URLSearchParams()
|
||||
if (params.schoolYearId != null) query.set('school_year_id', String(params.schoolYearId))
|
||||
if (params.parentId != null) query.set('parent_id', String(params.parentId))
|
||||
|
||||
const response = await apiFetch<ApiParentStatementResponse>(
|
||||
`/api/v1/parent/statements${query.toString() ? `?${query}` : ''}`,
|
||||
)
|
||||
|
||||
if (!response.data) {
|
||||
throw new Error('Parent statement returned no payload.')
|
||||
}
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
+6
-1
@@ -1,5 +1,5 @@
|
||||
import { apiUrl } from '../lib/apiOrigin'
|
||||
import { ApiHttpError, apiFetch, getStoredToken } from './http'
|
||||
import { ApiHttpError, apiFetch, applyStoredSchoolYearHeaders, getStoredToken } from './http'
|
||||
import type {
|
||||
AdministratorAbsenceFormResponse,
|
||||
AdministratorAbsenceSubmitResponse,
|
||||
@@ -595,6 +595,7 @@ export async function uploadEarlyDismissalSignature(formData: FormData): Promise
|
||||
const token = getStoredToken()
|
||||
const headers = new Headers({ Accept: 'application/json' })
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl('/api/v1/attendance/early-dismissals/signature'), {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
@@ -1224,6 +1225,7 @@ export async function openProtectedApiFile(path: string): Promise<void> {
|
||||
const headers = new Headers()
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
|
||||
const res = await fetch(apiUrl(path), { headers })
|
||||
if (!res.ok) {
|
||||
@@ -1255,6 +1257,7 @@ async function fetchMultipartJson<T>(
|
||||
const headers = new Headers({ Accept: 'application/json' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl(path), {
|
||||
method: init.method ?? 'POST',
|
||||
headers,
|
||||
@@ -1788,6 +1791,7 @@ export async function fetchPaypalTransactionsCsv(params?: { q?: string }): Promi
|
||||
const headers = new Headers({ Accept: 'text/csv' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const query = new URLSearchParams()
|
||||
if (params?.q) query.set('q', params.q)
|
||||
const suffix = query.size > 0 ? `?${query.toString()}` : ''
|
||||
@@ -2142,6 +2146,7 @@ export async function fetchReportCardPdf(studentId: number): Promise<Blob> {
|
||||
const headers = new Headers({ Accept: 'application/pdf' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
const res = await fetch(apiUrl(`/api/v1/reports/report-cards/students/${studentId}`), {
|
||||
headers,
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Teacher portal API (`Views/teacher/*` parity).
|
||||
* Laravel should expose matching routes under `/api/v1/teacher/...`.
|
||||
*/
|
||||
import { apiFetch, getStoredToken } from './http'
|
||||
import { apiFetch, applyStoredSchoolYearHeaders, getStoredToken } from './http'
|
||||
import { apiUrl } from '../lib/apiOrigin'
|
||||
|
||||
/** Response shape for `GET /api/v1/teacher/dashboard` (extend as backend grows). */
|
||||
@@ -47,6 +47,7 @@ export async function postTeacherMultipart<T>(path: string, formData: FormData):
|
||||
const headers = new Headers({ Accept: 'application/json' })
|
||||
const token = getStoredToken()
|
||||
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||
applyStoredSchoolYearHeaders(headers)
|
||||
|
||||
const url = isAbsoluteApiPath ? apiUrl(p) : apiUrl(`/api/v1/teacher${p}`)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ export type AuthUser = {
|
||||
id: number
|
||||
name: string
|
||||
roles: Record<string, boolean>
|
||||
permissions?: Record<string, boolean> | string[]
|
||||
class_section_id?: number | null
|
||||
class_section_name?: string | null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user