[Hooks] make use of curriculum context

This commit is contained in:
joonas-a
2026-09-29 13:51:15 +03:00
parent ce2a035111
commit fa21354b8b
11 changed files with 60 additions and 80 deletions
@@ -6,12 +6,11 @@ import Typography from '@mui/material/Typography'
import type { Dispatch, SetStateAction } from 'react'
import { StudentAmountLimiter } from '@/components/common/StudentAmountLimiter'
import { ExtendedCurriculumDetails } from '@/hooks/useCurriculums'
import { useCurriculum } from '@/hooks/useCurriculum'
type CourseTableModeSelectorProps = {
courseTableMode: 'curriculum' | 'all'
setCourseTableMode: Dispatch<SetStateAction<'curriculum' | 'all'>>
curriculum: ExtendedCurriculumDetails | null
studentAmountLimit: number
onStudentAmountLimitChange: (input: string) => void
}
@@ -20,47 +19,50 @@ export const CourseTableModeSelector = ({
courseTableMode,
onStudentAmountLimitChange,
setCourseTableMode,
curriculum,
studentAmountLimit,
}: CourseTableModeSelectorProps) => (
<RadioGroup>
<FormControlLabel
control={
<Radio
checked={courseTableMode === 'curriculum'}
onChange={() => setCourseTableMode('curriculum')}
size="small"
/>
}
label={
<Stack flexDirection="row" gap={1} sx={{ alignContent: 'center' }}>
<Typography fontWeight={500}>Curriculum</Typography>
<Typography
fontWeight={800}
sx={{
color: courseTableMode === 'curriculum' ? 'text.primary' : 'text.disabled',
}}
>
{curriculum?.name ?? 'unavailable'}
</Typography>
</Stack>
}
/>
<Stack direction="row" sx={{ alignItems: 'center', mt: '0.5em' }}>
}: CourseTableModeSelectorProps) => {
const { curriculum } = useCurriculum()
return (
<RadioGroup>
<FormControlLabel
control={
<>
<Radio checked={courseTableMode === 'all'} onChange={() => setCourseTableMode('all')} size="small" />
<StudentAmountLimiter
disabled={courseTableMode !== 'all'}
onStudentAmountLimitChange={value => onStudentAmountLimitChange(value.toString())}
studentAmountLimit={studentAmountLimit}
/>
</>
<Radio
checked={courseTableMode === 'curriculum'}
onChange={() => setCourseTableMode('curriculum')}
size="small"
/>
}
label={
<Stack flexDirection="row" gap={1} sx={{ alignContent: 'center' }}>
<Typography fontWeight={500}>Curriculum</Typography>
<Typography
fontWeight={800}
sx={{
color: courseTableMode === 'curriculum' ? 'text.primary' : 'text.disabled',
}}
>
{curriculum?.name ?? 'unavailable'}
</Typography>
</Stack>
}
label=""
value={'all'}
/>
</Stack>
</RadioGroup>
)
<Stack direction="row" sx={{ alignItems: 'center', mt: '0.5em' }}>
<FormControlLabel
control={
<>
<Radio checked={courseTableMode === 'all'} onChange={() => setCourseTableMode('all')} size="small" />
<StudentAmountLimiter
disabled={courseTableMode !== 'all'}
onStudentAmountLimitChange={value => onStudentAmountLimitChange(value.toString())}
studentAmountLimit={studentAmountLimit}
/>
</>
}
label=""
value={'all'}
/>
</Stack>
</RadioGroup>
)
}
@@ -5,7 +5,6 @@ import { FilterDegreeCoursesModal } from '@/components/PopulationComponents/Popu
import { PopulationCourseStats } from '@/components/PopulationCourseStats'
import { PopulationCourseStatsFlat } from '@/components/PopulationCourseStats/PopulationCourseStatsFlat'
import { SegmentDimmer } from '@/components/SegmentDimmer'
import { ExtendedCurriculumDetails } from '@/hooks/useCurriculums'
import { PopulationQuery } from '@/types/populationSearch'
import { FilteredCourse } from '@/util/coursesOfPopulation'
@@ -14,7 +13,6 @@ export const PopulationCourses = ({
query,
filteredCourses,
onlyIamRights,
curriculum,
courseTableMode,
studentAmountLimit,
setShowModules,
@@ -24,7 +22,6 @@ export const PopulationCourses = ({
query: Pick<PopulationQuery, 'programme' | 'years'>
filteredCourses: FilteredCourse[]
onlyIamRights: boolean
curriculum: ExtendedCurriculumDetails
courseTableMode: 'curriculum' | 'all'
studentAmountLimit: number
setShowModules: (input: boolean) => void
@@ -47,7 +44,6 @@ export const PopulationCourses = ({
{courseTableMode === 'curriculum' ? (
<PopulationCourseStats
courseTableMode={courseTableMode}
curriculum={curriculum}
filteredCourses={filteredCourses}
onlyIamRights={onlyIamRights}
pending={isLoading}
@@ -6,14 +6,13 @@ import { OodiTableExcelExport } from '@/components/OodiTable/excelExport'
import { IncludeSubstitutionsToggle } from '@/components/PopulationComponents/Students/IncludeSubstitutionsToggle'
import { useGetColumnDefinitions } from '@/components/PopulationComponents/Students/Table/CoursesTab/columnDefinitions'
import { useToggle } from '@/hooks/toggle'
import { ExtendedCurriculumDetails } from '@/hooks/useCurriculums'
import { useCurriculum } from '@/hooks/useCurriculum'
import { FilteredCourse } from '@/util/coursesOfPopulation'
import { CreditTypeCode, Name, ProgrammeCourse } from '@oodikone/shared/types'
import { FormattedStudent, StudentCourse } from '@oodikone/shared/types/studentData'
import { FilterDegreeCoursesModal } from '@/components/PopulationComponents/PopulationCourses/FilterDegreeCoursesModal'
type CoursesTabContainerProps = {
curriculum: ExtendedCurriculumDetails
students: FormattedStudent[]
courses: FilteredCourse[]
idToGroupIdMap: Record<string, string>
@@ -263,13 +262,8 @@ const gradeOrdering = ['0', 'Hyl.', 'TT', 'HT', '1', '2', '3', '4', '5', 'Hyv.']
const compareCourseGrades = (previous: StudentCourse, current: StudentCourse) =>
gradeOrdering.indexOf(previous.grade) <= gradeOrdering.indexOf(current.grade)
export const CoursesTabContainer = ({
curriculum,
students,
courses,
idToGroupIdMap,
programme,
}: CoursesTabContainerProps) => {
export const CoursesTabContainer = ({ students, courses, idToGroupIdMap, programme }: CoursesTabContainerProps) => {
const { curriculum } = useCurriculum()
const { visible: namesVisible } = useStudentNameVisibility()
const [includeSubstitutions, toggleIncludeSubstitutions] = useToggle(true)
@@ -279,7 +273,10 @@ export const CoursesTabContainer = ({
)
const curriculumCourses = useMemo(
() => [...curriculum.defaultProgrammeCourses, ...curriculum.secondProgrammeCourses].filter(nonVisible),
() =>
curriculum
? [...curriculum.defaultProgrammeCourses, ...curriculum.secondProgrammeCourses].filter(nonVisible)
: [],
[curriculum]
)
@@ -1,7 +1,7 @@
import { useMemo } from 'react'
import { ModulesTab } from '@/components/PopulationComponents/Students/Table/ModulesTab/ModulesTable'
import { ExtendedCurriculumDetails } from '@/hooks/useCurriculums'
import { useCurriculum } from '@/hooks/useCurriculum'
import { FilteredCourse } from '@/util/coursesOfPopulation'
import { createLocaleComparator } from '@/util/comparator'
import { formatISODate } from '@/util/timeAndDate'
@@ -86,18 +86,17 @@ const getDegreeProgrammeCodes = (curriculumModules): string[] => {
}
export const ModulesTabContainer = ({
curriculum,
students,
courses,
idToGroupIdMap,
programme,
}: {
curriculum: ExtendedCurriculumDetails | null | undefined
students: Student[]
courses: FilteredCourse[]
idToGroupIdMap: Record<string, string>
programme: string
}) => {
const { curriculum } = useCurriculum()
const curriculumModules = useMemo(
() => (curriculum ? [...curriculum.defaultProgrammeModules, ...curriculum.secondProgrammeModules] : []),
[curriculum]
@@ -17,7 +17,7 @@ import { CopyStudentNumbersHeader } from '@/components/OodiTable/common/CopyStud
import { OodiTableExcelExport } from '@/components/OodiTable/excelExport'
import { TableInfo } from '@/components/PopulationComponents/Students/Table/ProgressTab/info'
import { DateFormat } from '@/constants/date'
import { ExtendedCurriculumDetails } from '@/hooks/useCurriculums'
import { useCurriculum } from '@/hooks/useCurriculum'
import { useSemesters } from '@/hooks/useSemesters'
import { useGetProgressCriteriaQuery } from '@/redux/progressCriteria'
import { CheckIcon, CloseIcon, EditIcon, RemoveIcon, SwapHorizIcon } from '@/theme'
@@ -226,14 +226,12 @@ type Label = {
}
export const ProgressTable = ({
curriculum,
idToGroupIdMap,
students,
months,
programme,
studyGuidanceGroupProgramme,
}: {
curriculum?: ExtendedCurriculumDetails | null
idToGroupIdMap: IdToGroupId
students: FormattedStudent[]
months: number
@@ -242,6 +240,7 @@ export const ProgressTable = ({
}) => {
const { visible: namesVisible } = useStudentNameVisibility()
const { getTextIn } = useLanguage()
const { curriculum } = useCurriculum()
const { data: criteria } = useGetProgressCriteriaQuery({ programmeCode: programme }, { skip: !programme })
const { semesters: allSemesters } = useSemesters()
const isStudyGuidanceGroupProgramme = studyGuidanceGroupProgramme !== ''
@@ -13,7 +13,6 @@ import { type FormattedStudentData, GeneralTab } from '@/components/PopulationCo
import { ModulesTabContainer as ModulesTab } from '@/components/PopulationComponents/Students/Table/ModulesTab'
import { ProgressTable as ProgressTab } from '@/components/PopulationComponents/Students/Table/ProgressTab'
import { TagsTab } from '@/components/PopulationComponents/Students/Table/TagsTab'
import { ExtendedCurriculumDetails } from '@/hooks/useCurriculums'
import { FilteredCourse } from '@/util/coursesOfPopulation'
import { useParseQueryParams } from '@/util/queryparams'
import { isBachelorOrLicentiateProgramme } from '@/util/studyProgramme'
@@ -29,7 +28,6 @@ type PopulationDetails = CommonProps & {
variant: 'population'
programme: string
combinedProgramme?: string
curriculum: ExtendedCurriculumDetails | null
filteredCourses: FilteredCourse[]
idToGroupIdMap: Record<string, string>
}
@@ -40,7 +38,6 @@ type CoursePopulation = CommonProps & {
type StudyGuidanceGroup = CommonProps & {
variant: 'studyGuidanceGroupPopulation'
curriculum: ExtendedCurriculumDetails | null
studyGuidanceGroup: any
year: string
filteredCourses: FilteredCourse[]
@@ -63,7 +60,6 @@ export const PopulationStudents = ({
variant,
programme,
combinedProgramme,
curriculum,
filteredStudents,
filteredCourses,
idToGroupIdMap,
@@ -101,7 +97,6 @@ export const PopulationStudents = ({
Courses: (
<CoursesTab
courses={filteredCourses ?? []}
curriculum={curriculum} // TODO: add guard for missing curriculum (it should never be missing)
idToGroupIdMap={idToGroupIdMap ?? {}}
students={filteredStudents}
programme={programme}
@@ -110,7 +105,6 @@ export const PopulationStudents = ({
Modules: (
<ModulesTab
courses={filteredCourses ?? []}
curriculum={curriculum}
idToGroupIdMap={idToGroupIdMap ?? {}}
students={filteredStudents}
programme={programme}
@@ -119,7 +113,6 @@ export const PopulationStudents = ({
Tags: <TagsTab combinedProgramme={combinedProgramme} programme={programme} students={filteredStudents} />,
Progress: (
<ProgressTab
curriculum={curriculum}
idToGroupIdMap={idToGroupIdMap ?? {}}
months={months ?? Infinity}
programme={programme}
@@ -5,7 +5,7 @@ import { useState, useEffect } from 'react'
import { GradeDistribution } from '@/components/PopulationCourseStats/GradeDistribution'
import { PassFailEnrollments } from '@/components/PopulationCourseStats/PassFailEnrollments'
import { PassingSemesters } from '@/components/PopulationCourseStats/PassingSemesters'
import { ExtendedCurriculumDetails } from '@/hooks/useCurriculums'
import { useCurriculum } from '@/hooks/useCurriculum'
import { FilteredCourse, CourseModule, FilteredProgrammeCourse } from '@/util/coursesOfPopulation'
import type { CourseStats } from '@oodikone/shared/routes/populations'
import type { Module, CurriculumDetails } from '@oodikone/shared/types'
@@ -14,7 +14,6 @@ type PopulationCourseStatsProps = {
filteredCourses: FilteredCourse[]
pending: boolean
onlyIamRights: boolean
curriculum: ExtendedCurriculumDetails
courseTableMode: 'all' | 'curriculum'
showModules: boolean
setShowModules: (input: boolean) => void
@@ -33,15 +32,17 @@ export const PopulationCourseStats = ({
filteredCourses,
pending,
onlyIamRights,
curriculum,
courseTableMode,
showModules,
setShowModules,
}: PopulationCourseStatsProps) => {
const { curriculum } = useCurriculum()
const [modules, setModules] = useState<CourseModule[]>([])
const [tab, setTab] = useState(0)
useEffect(() => {
if (!curriculum) return
// Change courses type from FilteredCourse[] to FilteredProgrammeCourse[] + add module-field to object so we can deconstruct it below
const modules: Record<
string,
@@ -128,14 +128,12 @@ const PopulationDetailsContent = ({
<>
<CourseTableModeSelector
courseTableMode={courseTableMode}
curriculum={curriculum}
onStudentAmountLimitChange={onStudentAmountLimitChange}
setCourseTableMode={setCourseTableMode}
studentAmountLimit={studentAmountLimit}
/>
<PopulationCourses
courseTableMode={courseTableMode}
curriculum={curriculum}
filteredCourses={filteredCourses}
isLoading={isLoading}
onlyIamRights={onlyIamRights}
@@ -153,7 +151,6 @@ const PopulationDetailsContent = ({
content: (
<PopulationStudents
combinedProgramme={combinedProgramme}
curriculum={curriculum}
filteredCourses={filteredCourses}
filteredStudents={filteredStudents}
idToGroupIdMap={idToGroupIdMap}
@@ -124,7 +124,6 @@ const SingleStudyGuidanceGroupPanelsContent = ({
title: 'Courses of population',
content: (
<StudyGuidanceGroupPopulationCourses
curriculum={curriculum}
filteredCourses={filteredCourses}
studyProgramme={group.tags?.studyProgramme ? programme : null}
year={groupYear}
@@ -136,7 +135,6 @@ const SingleStudyGuidanceGroupPanelsContent = ({
content: (
// @ts-expect-error FIX typing
<PopulationStudents
curriculum={curriculum}
filteredCourses={filteredCourses}
filteredStudents={filteredStudents}
generalTabColumnFunction={() => columnsGeneralTab({ group })}
@@ -6,7 +6,7 @@ import { PopulationCourseStats } from '@/components/PopulationCourseStats'
import { PopulationCourseStatsFlat } from '@/components/PopulationCourseStats/PopulationCourseStatsFlat'
import { useDebouncedState } from '@/hooks/debouncedState'
export const StudyGuidanceGroupPopulationCourses = ({ filteredCourses, studyProgramme, year, curriculum }) => {
export const StudyGuidanceGroupPopulationCourses = ({ filteredCourses, studyProgramme, year }) => {
const [studentAmountLimit, setStudentAmountLimit] = useDebouncedState(0, 1000)
const curriculumsAvailable = studyProgramme && year
const [courseTableMode, setCourseTableMode] = useState<'all' | 'curriculum'>(
@@ -23,7 +23,6 @@ export const StudyGuidanceGroupPopulationCourses = ({ filteredCourses, studyProg
{curriculumsAvailable ? (
<CourseTableModeSelector
courseTableMode={courseTableMode}
curriculum={curriculum}
onStudentAmountLimitChange={onStudentAmountLimitChange}
setCourseTableMode={setCourseTableMode}
studentAmountLimit={studentAmountLimit}
@@ -37,7 +36,6 @@ export const StudyGuidanceGroupPopulationCourses = ({ filteredCourses, studyProg
{courseTableMode === 'curriculum' ? (
<PopulationCourseStats
courseTableMode={courseTableMode}
curriculum={curriculum}
filteredCourses={filteredCourses}
onlyIamRights={onlyIamRights}
pending={false}
@@ -30,7 +30,7 @@ export const CurriculumProvider = ({
return <CurriculumContext.Provider value={value}>{children}</CurriculumContext.Provider>
}
/** Context variant of the curriculum hook */
/** Context-aware variant of the curriculum hook. Use this in population statistics views. */
export const useCurriculum = () => {
const context = useContext(CurriculumContext)
if (!context) {