add school year model

This commit is contained in:
root
2026-06-07 00:52:04 -04:00
parent c4d7a06a17
commit 8e79201a3c
32 changed files with 2031 additions and 213 deletions
+30 -15
View File
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useState, type FormEvent, type ReactNode } from 're
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom'
import './AdminDailyAttendance.css'
import { ApiHttpError } from '../api/http'
import { useSchoolYearOptions } from '../hooks/useSchoolYearOptions'
import {
assignTeacherClass,
assignStudentClass,
@@ -1050,12 +1051,6 @@ export function AdminCalendarEditPage() {
/** School calendar admin — `GET /api/v1/settings/school-calendar/events` (JWT). SPA: `/app/administrator/events` or `calendar_view`. */
function currentSchoolYear(): string {
const now = new Date()
const y = now.getFullYear()
return now.getMonth() >= 8 ? `${y}-${y + 1}` : `${y - 1}-${y}`
}
export function AdminCalendarViewPage() {
const navigate = useNavigate()
const [searchParams, setSearchParams] = useSearchParams()
@@ -1063,12 +1058,15 @@ export function AdminCalendarViewPage() {
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const schoolYear = searchParams.get('school_year') ?? ''
const { options, currentYear } = useSchoolYearOptions({
preferredYear: schoolYear,
})
useEffect(() => {
if (!schoolYear) {
setSearchParams(new URLSearchParams({ school_year: currentSchoolYear() }), { replace: true })
if (!schoolYear && currentYear) {
setSearchParams(new URLSearchParams({ school_year: currentYear }), { replace: true })
}
}, [])
}, [currentYear, schoolYear, setSearchParams])
async function load() {
setLoading(true)
@@ -1124,14 +1122,27 @@ export function AdminCalendarViewPage() {
>
<div>
<label htmlFor="cal-school-year" className="form-label">School Year</label>
<input id="cal-school-year" name="school_year" className="form-control" defaultValue={schoolYear} placeholder="e.g. 2025-2026" />
<select
id="cal-school-year"
name="school_year"
className="form-select"
defaultValue={schoolYear || currentYear}
>
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</div>
<div className="d-flex gap-2 align-self-end">
<button className="btn btn-secondary" type="submit">Apply</button>
<button
className="btn btn-outline-secondary"
type="button"
onClick={() => setSearchParams(new URLSearchParams({ school_year: currentSchoolYear() }))}
onClick={() =>
setSearchParams(new URLSearchParams(currentYear ? { school_year: currentYear } : {}))
}
>
Reset
</button>
@@ -1307,6 +1318,10 @@ export function AdminClassAssignmentPage() {
key: 'school_id',
direction: 'asc',
})
const { options, selectedYear: defaultYear } = useSchoolYearOptions({
legacyYears: schoolYears,
preferredYear: selectedYear,
})
async function load(year?: string | null) {
setLoading(true)
@@ -1316,7 +1331,7 @@ export function AdminClassAssignmentPage() {
const classSections = data.classSections ?? []
setSections(classSections)
setSchoolYears(data.schoolYears ?? [])
setSelectedYear(data.selectedYear ?? data.schoolYear ?? '')
setSelectedYear(data.selectedYear ?? data.schoolYear ?? defaultYear)
setSelectedSemester(data.selectedSemester ?? data.semester ?? '')
setExpandedSections(new Set(classSections.length > 0 ? ['0'] : []))
setError(null)
@@ -1397,11 +1412,11 @@ export function AdminClassAssignmentPage() {
<select
className="form-select form-select-sm"
style={{ minWidth: 200 }}
value={selectedYear}
value={selectedYear || defaultYear}
onChange={(event) => setSelectedYear(event.target.value)}
>
{schoolYears.map((year) => (
<option key={year} value={year}>{year}</option>
{options.map((year) => (
<option key={year.value} value={year.value}>{year.label}</option>
))}
</select>
</div>