mirror of
https://github.com/UniversityOfHelsinkiCS/oodikone.git
synced 2026-10-12 19:03:39 +03:00
[Study programme] Extract util isBachelorOrLicentiateProgramme
This commit is contained in:
@@ -4,15 +4,18 @@ import { Button, Dropdown, Icon, Label, Table } from 'semantic-ui-react'
|
||||
import { useLanguage } from '@/components/LanguagePicker/useLanguage'
|
||||
import { useRemoveCourseExclusionMutation, useSetCourseExclusionMutation } from '@/redux/courseExclusions'
|
||||
import { useAddProgressCriteriaCourseMutation } from '@/redux/progressCriteria'
|
||||
import { Module } from '@/shared/types'
|
||||
import { Module, ProgressCriteria } from '@/shared/types'
|
||||
import { isBachelorOrLicentiateProgramme } from '@/util/studyProgramme'
|
||||
|
||||
const getYear = criterionYear => {
|
||||
if (criterionYear === 1) return 'yearOne'
|
||||
if (criterionYear === 2) return 'yearTwo'
|
||||
if (criterionYear === 3) return 'yearThree'
|
||||
if (criterionYear === 4) return 'yearFour'
|
||||
if (criterionYear === 5) return 'yearFive'
|
||||
return 'yearSix'
|
||||
const getYear = (criterionYear: number) => {
|
||||
return {
|
||||
1: 'yearOne',
|
||||
2: 'yearTwo',
|
||||
3: 'yearThree',
|
||||
4: 'yearFour',
|
||||
5: 'yearFive',
|
||||
6: 'yearSix',
|
||||
}[criterionYear]
|
||||
}
|
||||
|
||||
const moduleVisibilityColor = visibility => {
|
||||
@@ -29,13 +32,13 @@ const moduleVisibilityColor = visibility => {
|
||||
export const DegreeCourseTable = ({
|
||||
combinedProgramme,
|
||||
criteria,
|
||||
curriculum,
|
||||
curriculumVersion,
|
||||
modules: initialModules,
|
||||
studyProgramme,
|
||||
}: {
|
||||
combinedProgramme: string
|
||||
criteria
|
||||
curriculum
|
||||
criteria: ProgressCriteria
|
||||
curriculumVersion: string[]
|
||||
modules: Module[]
|
||||
studyProgramme: string
|
||||
}) => {
|
||||
@@ -46,14 +49,14 @@ export const DegreeCourseTable = ({
|
||||
const [removeExclusion] = useRemoveCourseExclusionMutation()
|
||||
const [addProgressCriteriaCourse] = useAddProgressCriteriaCourseMutation()
|
||||
|
||||
const version = curriculum.version?.join(',')
|
||||
const version = curriculumVersion.join(',')
|
||||
useEffect(() => {
|
||||
setModules(initialModules)
|
||||
}, [initialModules])
|
||||
|
||||
const setModuleVisibility = (code, newVisibility) => {
|
||||
// Same course can be in many modules, so change them all
|
||||
const courseCodes = modules.find(({ module }) => module === code).courses.map(course => course.code)
|
||||
const courseCodes = modules.find(module => module.moduleName === code).courses.map(course => course.code)
|
||||
setModules(
|
||||
modules.map(module => ({
|
||||
...module,
|
||||
@@ -94,7 +97,7 @@ export const DegreeCourseTable = ({
|
||||
}
|
||||
|
||||
const excludeAll = code => {
|
||||
const module = modules.find(({ module }) => module === code)
|
||||
const module = modules.find(module => module.moduleName === code)
|
||||
const excludeFromProgramme = combinedProgramme === '' ? studyProgramme : combinedProgramme
|
||||
setExclusion({
|
||||
programmeCode: excludeFromProgramme,
|
||||
@@ -105,7 +108,7 @@ export const DegreeCourseTable = ({
|
||||
}
|
||||
|
||||
const deleteAll = code => {
|
||||
const module = modules.find(({ module }) => module === code)
|
||||
const module = modules.find(module => module.moduleName === code)
|
||||
removeExclusion({
|
||||
programmeCode: studyProgramme,
|
||||
courseCodes: module.courses.map(course => course.code),
|
||||
@@ -132,7 +135,7 @@ export const DegreeCourseTable = ({
|
||||
}
|
||||
|
||||
const calculateModuleVisibility = code => {
|
||||
const module = modules.find(({ module }) => module === code)
|
||||
const module = modules.find(module => module.moduleName === code)
|
||||
if (!module.courses) {
|
||||
return 'no courses'
|
||||
}
|
||||
@@ -185,11 +188,11 @@ export const DegreeCourseTable = ({
|
||||
onClick={() => {
|
||||
const year = getYear(criterionYear)
|
||||
const courses = criteria.courses ? [...criteria.courses[year], course.code] : [course.code]
|
||||
addProgressCriteriaCourse({
|
||||
void addProgressCriteriaCourse({
|
||||
programmeCode: studyProgramme,
|
||||
courses,
|
||||
year: criterionYear,
|
||||
version: curriculum.version,
|
||||
version: curriculumVersion,
|
||||
})
|
||||
}}
|
||||
>
|
||||
@@ -202,7 +205,7 @@ export const DegreeCourseTable = ({
|
||||
onClick={() => {
|
||||
const year = getYear(criterionYear)
|
||||
const filteredCourses = criteria?.courses[year]?.filter(courseCode => courseCode !== course.code)
|
||||
addProgressCriteriaCourse({ programmeCode: studyProgramme, courses: filteredCourses, year: criterionYear })
|
||||
void addProgressCriteriaCourse({ programmeCode: studyProgramme, courses: filteredCourses, year: criterionYear })
|
||||
}}
|
||||
>
|
||||
{`Remove criterion for year ${criterionYear}`}
|
||||
@@ -271,9 +274,7 @@ export const DegreeCourseTable = ({
|
||||
<Table.HeaderCell>Name</Table.HeaderCell>
|
||||
<Table.HeaderCell>Code</Table.HeaderCell>
|
||||
<Table.HeaderCell>Visibility label</Table.HeaderCell>
|
||||
{(studyProgramme.includes('KH') || ['MH30_001', 'MH30_003'].includes(studyProgramme)) && (
|
||||
<Table.HeaderCell>Criterion labels</Table.HeaderCell>
|
||||
)}
|
||||
{isBachelorOrLicentiateProgramme(studyProgramme) && <Table.HeaderCell>Criterion labels</Table.HeaderCell>}
|
||||
<Table.HeaderCell>
|
||||
{studyProgramme.includes('KH') || ['MH30_001', 'MH30_003'].includes(studyProgramme)
|
||||
? 'Set labels'
|
||||
@@ -282,30 +283,32 @@ export const DegreeCourseTable = ({
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{modules.map(({ module, courses }) => (
|
||||
<Fragment key={`fragment-${module}`}>
|
||||
<Table.Row key={module}>
|
||||
<Table.Cell onClick={() => toggleVisible(module)} style={{ cursor: 'pointer' }}>
|
||||
<Icon name={isVisible(module) ? 'angle down' : 'angle right'} />
|
||||
<b>{courses[0] && courses[0].parent_name ? getTextIn(courses[0].parent_name) : module}</b>
|
||||
{modules.map(({ moduleName, courses }) => (
|
||||
<Fragment key={`fragment-${moduleName}`}>
|
||||
<Table.Row key={moduleName}>
|
||||
<Table.Cell onClick={() => toggleVisible(moduleName)} style={{ cursor: 'pointer' }}>
|
||||
<Icon name={isVisible(moduleName) ? 'angle down' : 'angle right'} />
|
||||
<b>{courses[0] && courses[0].parent_name ? getTextIn(courses[0].parent_name) : moduleName}</b>
|
||||
</Table.Cell>
|
||||
<Table.Cell>{module}</Table.Cell>
|
||||
<Table.Cell>{moduleName}</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Label
|
||||
color={moduleVisibilityColor(calculateModuleVisibility(module))}
|
||||
content={calculateModuleVisibility(module)}
|
||||
color={moduleVisibilityColor(calculateModuleVisibility(moduleName))}
|
||||
content={calculateModuleVisibility(moduleName)}
|
||||
/>
|
||||
</Table.Cell>
|
||||
{(studyProgramme.includes('KH') || ['MH30_001', 'MH30_003'].includes(studyProgramme)) && <Table.Cell />}
|
||||
{isBachelorOrLicentiateProgramme(studyProgramme) && <Table.Cell />}
|
||||
<Table.Cell>
|
||||
{calculateModuleVisibility(module) === 'hidden' ? showAllButton(module) : hideAllButton(module)}
|
||||
{calculateModuleVisibility(moduleName) === 'hidden'
|
||||
? showAllButton(moduleName)
|
||||
: hideAllButton(moduleName)}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{isVisible(module) &&
|
||||
{isVisible(moduleName) &&
|
||||
courses
|
||||
.sort((a, b) => a.code.localeCompare(b.code))
|
||||
.map(course => (
|
||||
<Table.Row key={`${module}/${course.code}`}>
|
||||
<Table.Row key={`${moduleName}/${course.code}`}>
|
||||
<Table.Cell>{getTextIn(course.name)}</Table.Cell>
|
||||
<Table.Cell>{course.code}</Table.Cell>
|
||||
<Table.Cell>
|
||||
@@ -314,7 +317,7 @@ export const DegreeCourseTable = ({
|
||||
content={course.visible.visibility ? 'visible' : 'hidden'}
|
||||
/>
|
||||
</Table.Cell>
|
||||
{(studyProgramme.includes('KH') || ['MH30_001', 'MH30_003'].includes(studyProgramme)) && (
|
||||
{isBachelorOrLicentiateProgramme(studyProgramme) && (
|
||||
<Table.Cell>
|
||||
{criteria?.courses?.yearOne?.includes(course.code) && <Label color="blue" content="year 1" />}
|
||||
{criteria?.courses?.yearTwo?.includes(course.code) && <Label color="blue" content="year 2" />}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react'
|
||||
|
||||
import { useGetProgressCriteriaQuery } from '@/redux/progressCriteria'
|
||||
import { CurriculumDetails, Module, ProgrammeCourse, ProgressCriteria } from '@/shared/types'
|
||||
import { isBachelorOrLicentiateProgramme } from '@/util/studyProgramme'
|
||||
import { CreditCriteriaSection } from './CreditCriteriaSection'
|
||||
import { CurriculumSection } from './CurriculumSection'
|
||||
import { DegreeCourseTable } from './DegreeCourseTable'
|
||||
@@ -28,49 +29,35 @@ export const DegreeCoursesTab = ({
|
||||
}
|
||||
const criteria = progressCriteria ?? emptyCriteria
|
||||
|
||||
const getModules = (courses: ProgrammeCourse[]): Module[] => {
|
||||
const modules: Record<string, ProgrammeCourse[]> = {}
|
||||
courses.forEach(course => {
|
||||
const code = course.parent_code!
|
||||
if (!modules[code]) {
|
||||
modules[code] = []
|
||||
}
|
||||
modules[code].push(course)
|
||||
})
|
||||
|
||||
return orderBy(
|
||||
Object.entries(modules).map(([moduleName, courses]) => ({
|
||||
courses,
|
||||
moduleName,
|
||||
moduleOrder: courses[0].module_order,
|
||||
})),
|
||||
module => module.moduleName
|
||||
)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!curriculum?.defaultProgrammeCourses?.length) {
|
||||
return
|
||||
}
|
||||
const defaultModules: Record<string, ProgrammeCourse[]> = {}
|
||||
const secondProgrammeModules: Record<string, ProgrammeCourse[]> = {}
|
||||
curriculum.defaultProgrammeCourses.forEach(course => {
|
||||
const code = course.parent_code
|
||||
if (!defaultModules[code]) {
|
||||
defaultModules[code] = []
|
||||
}
|
||||
defaultModules[code].push(course)
|
||||
})
|
||||
if (combinedProgramme) {
|
||||
curriculum.secondProgrammeCourses.forEach(course => {
|
||||
const code = course.parent_code
|
||||
if (!secondProgrammeModules[code]) {
|
||||
secondProgrammeModules[code] = []
|
||||
}
|
||||
secondProgrammeModules[code].push(course)
|
||||
})
|
||||
}
|
||||
|
||||
setDefaultProgrammeModules(
|
||||
orderBy(
|
||||
Object.entries(defaultModules).map(([module, courses]) => ({
|
||||
module,
|
||||
courses,
|
||||
module_order: courses[0].module_order,
|
||||
})),
|
||||
module => module.module
|
||||
)
|
||||
)
|
||||
setSecondProgrammeModules(
|
||||
orderBy(
|
||||
Object.entries(secondProgrammeModules).map(([module, courses]) => ({
|
||||
module,
|
||||
courses,
|
||||
module_order: courses[0].module_order,
|
||||
})),
|
||||
module => module.module
|
||||
)
|
||||
)
|
||||
setDefaultProgrammeModules(getModules(curriculum.defaultProgrammeCourses))
|
||||
if (combinedProgramme) {
|
||||
setSecondProgrammeModules(getModules(curriculum.secondProgrammeCourses))
|
||||
}
|
||||
}, [combinedProgramme, curriculum])
|
||||
|
||||
return (
|
||||
@@ -80,23 +67,23 @@ export const DegreeCoursesTab = ({
|
||||
setCurriculum={setCurriculum}
|
||||
year={year}
|
||||
/>
|
||||
{(studyProgramme.includes('KH') || ['MH30_001', 'MH30_003'].includes(studyProgramme)) && (
|
||||
{isBachelorOrLicentiateProgramme(studyProgramme) && (
|
||||
<CreditCriteriaSection criteria={criteria} studyProgramme={studyProgramme} />
|
||||
)}
|
||||
{defaultProgrammeModules && defaultProgrammeModules.length > 1 && (
|
||||
{defaultProgrammeModules.length > 1 && curriculum && (
|
||||
<DegreeCourseTable
|
||||
combinedProgramme=""
|
||||
criteria={criteria}
|
||||
curriculum={curriculum}
|
||||
curriculumVersion={curriculum.version}
|
||||
modules={defaultProgrammeModules}
|
||||
studyProgramme={studyProgramme}
|
||||
/>
|
||||
)}
|
||||
{secondProgrammeModules.length > 0 && (
|
||||
{secondProgrammeModules.length > 0 && curriculum && (
|
||||
<DegreeCourseTable
|
||||
combinedProgramme={combinedProgramme}
|
||||
criteria={criteria}
|
||||
curriculum={curriculum}
|
||||
curriculumVersion={curriculum.version}
|
||||
modules={secondProgrammeModules}
|
||||
studyProgramme={studyProgramme}
|
||||
/>
|
||||
|
||||
@@ -9,3 +9,7 @@ export const getGraduationGraphTitle = (studyProgramme: string, doCombo = false)
|
||||
if (studyProgramme.includes('MH')) return 'Master study right'
|
||||
return 'Doctoral study right'
|
||||
}
|
||||
|
||||
export const isBachelorOrLicentiateProgramme = (studyProgramme: string) => {
|
||||
return studyProgramme.includes('KH') || ['MH30_001', 'MH30_003'].includes(studyProgramme)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Name } from './name'
|
||||
import { ProgrammeCourse, ProgrammeModule } from './studyProgramme'
|
||||
|
||||
export type CurriculumOption = {
|
||||
id: string
|
||||
@@ -7,65 +8,6 @@ export type CurriculumOption = {
|
||||
validFrom: Date
|
||||
}
|
||||
|
||||
export type Module = {
|
||||
courses: ProgrammeCourse[]
|
||||
module: string // ? Should this be called code or moduleCode?
|
||||
module_order: number
|
||||
}
|
||||
|
||||
// TODO: Format for frontend and drop irrelevant fields
|
||||
export type ProgrammeCourse = {
|
||||
code: string
|
||||
created_at: string
|
||||
curriculum_period_ids: string[]
|
||||
degree_programme_type: string | null
|
||||
group_id: string
|
||||
id: string
|
||||
label: {
|
||||
id: string
|
||||
label: string
|
||||
orderNumber: number
|
||||
}
|
||||
minimum_credits: number | null
|
||||
module_order: number
|
||||
name: Name
|
||||
order: number
|
||||
organization_id: string | null
|
||||
parent_code: string
|
||||
parent_id: string | null
|
||||
study_level: string | null
|
||||
type: string
|
||||
updated_at: string
|
||||
valid_from: string
|
||||
valid_to: string | null
|
||||
visible: {
|
||||
id: string | null
|
||||
visible: boolean
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Format for frontend and drop irrelevant fields
|
||||
export type ProgrammeModule = {
|
||||
code: string
|
||||
created_at: string
|
||||
curriculum_period_ids: string[]
|
||||
degree_programme_type: string | null
|
||||
group_id: string
|
||||
id: string
|
||||
minimum_credits: number | null
|
||||
module_order: number
|
||||
name: Name
|
||||
order: number
|
||||
organization_id: string | null
|
||||
parent_code: string | null
|
||||
parent_id: string | null
|
||||
study_level: string | null
|
||||
type: string
|
||||
updated_at: string
|
||||
valid_from: string
|
||||
valid_to: string | null
|
||||
}
|
||||
|
||||
export type CurriculumDetails = {
|
||||
defaultProgrammeCourses: ProgrammeCourse[]
|
||||
defaultProgrammeModules: ProgrammeModule[]
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
export type {
|
||||
CurriculumDetails,
|
||||
CurriculumOption,
|
||||
CurriculumPeriod,
|
||||
Module,
|
||||
ProgrammeCourse,
|
||||
ProgrammeModule,
|
||||
} from './curriculum'
|
||||
export type { CurriculumDetails, CurriculumOption, CurriculumPeriod } from './curriculum'
|
||||
export type { DetailedProgrammeRights } from './detailedProgrammeRights'
|
||||
export type { Graduated, SpecialGroups, ProgrammeFilter, StatsType, YearType } from './faculty'
|
||||
export type {
|
||||
@@ -22,6 +15,9 @@ export type { Role } from './role'
|
||||
export type {
|
||||
GraduationTimes,
|
||||
MedianEntry,
|
||||
Module,
|
||||
ProgrammeCourse,
|
||||
ProgrammeModule,
|
||||
ProgrammeOrStudyTrackGraduationStats,
|
||||
StudyTrackStats,
|
||||
} from './studyProgramme'
|
||||
|
||||
@@ -43,3 +43,44 @@ export type StudyTrackStats = {
|
||||
studyTracks: Record<string, string | Name>
|
||||
years: string[]
|
||||
}
|
||||
|
||||
// TODO: Format for frontend and drop irrelevant fields
|
||||
export type ProgrammeModule = {
|
||||
code: string
|
||||
created_at: string
|
||||
curriculum_period_ids: string[]
|
||||
degree_programme_type: string | null
|
||||
group_id: string
|
||||
id: string
|
||||
minimum_credits: number | null
|
||||
module_order: number
|
||||
name: Name
|
||||
order: number
|
||||
organization_id: string | null
|
||||
parent_code: string | null
|
||||
parent_id: string | null
|
||||
study_level: string | null
|
||||
type: string
|
||||
updated_at: string
|
||||
valid_from: string
|
||||
valid_to: string | null
|
||||
}
|
||||
|
||||
// TODO: Format for frontend and drop irrelevant fields
|
||||
export type ProgrammeCourse = ProgrammeModule & {
|
||||
label: {
|
||||
id: string
|
||||
label: string
|
||||
orderNumber: number
|
||||
}
|
||||
visibility: {
|
||||
id: string | null
|
||||
visible: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export type Module = {
|
||||
courses: ProgrammeCourse[]
|
||||
moduleName: string
|
||||
moduleOrder: number
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user