mirror of
https://github.com/UniversityOfHelsinkiCS/oodikone.git
synced 2026-10-12 19:03:39 +03:00
[Hooks] make use of curriculum context
This commit is contained in:
@@ -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}
|
||||
|
||||
+7
-10
@@ -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]
|
||||
)
|
||||
|
||||
|
||||
+2
-3
@@ -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]
|
||||
|
||||
+2
-3
@@ -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}
|
||||
|
||||
-2
@@ -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 })}
|
||||
|
||||
+1
-3
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user