From abcd00cbadcae9f2db5d44623bdf3cf72793ae6c Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 5 Nov 2024 10:00:41 +0200 Subject: [PATCH 01/13] [SegmentDimmer] Convert to TypeScript --- .../src/components/SegmentDimmer/{index.jsx => index.tsx} | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) rename services/frontend/src/components/SegmentDimmer/{index.jsx => index.tsx} (50%) diff --git a/services/frontend/src/components/SegmentDimmer/index.jsx b/services/frontend/src/components/SegmentDimmer/index.tsx similarity index 50% rename from services/frontend/src/components/SegmentDimmer/index.jsx rename to services/frontend/src/components/SegmentDimmer/index.tsx index 904c60e882..b2286d6ab4 100644 --- a/services/frontend/src/components/SegmentDimmer/index.jsx +++ b/services/frontend/src/components/SegmentDimmer/index.tsx @@ -1,6 +1,10 @@ import { Dimmer, Loader } from 'semantic-ui-react' -export const SegmentDimmer = ({ isLoading = false }) => ( +interface SegmentDimmerProps { + isLoading?: boolean +} + +export const SegmentDimmer = ({ isLoading = false }: SegmentDimmerProps) => ( Loading From 517638a44eb9370529783f39589d27a92e03ec3d Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 5 Nov 2024 10:01:47 +0200 Subject: [PATCH 02/13] [facultyHelpers] Convert to TypeScript --- .../{facultyHelpers.js => facultyHelpers.ts} | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) rename services/frontend/src/components/FacultyStatistics/{facultyHelpers.js => facultyHelpers.ts} (84%) diff --git a/services/frontend/src/components/FacultyStatistics/facultyHelpers.js b/services/frontend/src/components/FacultyStatistics/facultyHelpers.ts similarity index 84% rename from services/frontend/src/components/FacultyStatistics/facultyHelpers.js rename to services/frontend/src/components/FacultyStatistics/facultyHelpers.ts index e0f5bf4872..84969ef30a 100644 --- a/services/frontend/src/components/FacultyStatistics/facultyHelpers.js +++ b/services/frontend/src/components/FacultyStatistics/facultyHelpers.ts @@ -16,9 +16,9 @@ const regexValuesAll = [ /^Y/, /\d$/, /^\d.*e$/, -] +] as const -const testKey = value => { +const testKey = (value: string) => { for (let i = 0; i < regexValuesAll.length; i++) { if (regexValuesAll[i].test(value)) { return i @@ -27,7 +27,7 @@ const testKey = value => { return 6 } -export const sortProgrammeKeys = (programmeKeys, faculty) => { +export const sortProgrammeKeys = (programmeKeys: string[][], faculty: string) => { try { return programmeKeys.sort((a, b) => { if (a[1].includes(faculty) && !b[1].includes(faculty)) return -1 @@ -36,9 +36,7 @@ export const sortProgrammeKeys = (programmeKeys, faculty) => { if (!a[1].includes(faculty) && b[1].startsWith('T') && !a[1].includes('T')) return 1 if (a[1].startsWith('LIS') && !b[1].includes(faculty) && !b[1].includes('LIS')) return -1 if (!a[1].includes(faculty) && b[1].startsWith('LIS') && !a[1].includes('LIS')) return 1 - if (testKey(a[1]) - testKey(b[1]) === 0) { - return a[0].localeCompare(b[0]) - } + if (testKey(a[1]) - testKey(b[1]) === 0) return a[0].localeCompare(b[0]) return testKey(a[1]) - testKey(b[1]) }) } catch (error) { From 49da696a0b0dd58a21b10cc8dd0ea936058b02c8 Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 5 Nov 2024 10:26:52 +0200 Subject: [PATCH 03/13] [ProgressOfStudents] Convert to TypeScript --- ...gressOfStudents.jsx => ProgressOfStudents.tsx} | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) rename services/frontend/src/components/StudyProgramme/StudyTrackOverview/{ProgressOfStudents.jsx => ProgressOfStudents.tsx} (84%) diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents.jsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents.tsx similarity index 84% rename from services/frontend/src/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents.jsx rename to services/frontend/src/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents.tsx index f035289378..ba7714a67c 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents.jsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents.tsx @@ -1,7 +1,20 @@ import { BarChart } from './BarChart' import { BasicDataTable } from './BasicDataTable' -export const ProgressOfStudents = ({ progressStats, progressComboStats, track, years }) => { +interface ProgressStats { + chartStats: Array<{ data: number[]; name: string }> + tableStats: Array> + tableTitles: string[] +} + +interface ProgressOfStudentsProps { + progressStats: ProgressStats + progressComboStats: ProgressStats + track: string + years: string[] +} + +export const ProgressOfStudents = ({ progressStats, progressComboStats, track, years }: ProgressOfStudentsProps) => { return (
{progressComboStats != null && ( From 80cffc5fbf421ed1989011ba0a14c244408ce4d2 Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 5 Nov 2024 11:32:15 +0200 Subject: [PATCH 04/13] [StudyTrackOverview] Convert most components to TypeScript --- services/frontend/src/common/index.js | 9 ++ .../FacultyStudentDataTable.jsx | 11 +- .../{BarChart.jsx => BarChart.tsx} | 15 +- ...{BasicDataTable.jsx => BasicDataTable.tsx} | 20 ++- .../StudyTrackOverview/PopulationLink.jsx | 77 ---------- .../StudyTrackOverview/PopulationLink.tsx | 131 ++++++++++++++++++ .../StudyTrackDataTable.jsx | 26 ++-- ...ackSelector.jsx => StudyTrackSelector.tsx} | 30 ++-- 8 files changed, 200 insertions(+), 119 deletions(-) rename services/frontend/src/components/StudyProgramme/StudyTrackOverview/{BarChart.jsx => BarChart.tsx} (84%) rename services/frontend/src/components/StudyProgramme/StudyTrackOverview/{BasicDataTable.jsx => BasicDataTable.tsx} (62%) delete mode 100644 services/frontend/src/components/StudyProgramme/StudyTrackOverview/PopulationLink.jsx create mode 100644 services/frontend/src/components/StudyProgramme/StudyTrackOverview/PopulationLink.tsx rename services/frontend/src/components/StudyProgramme/StudyTrackOverview/{StudyTrackSelector.jsx => StudyTrackSelector.tsx} (55%) diff --git a/services/frontend/src/common/index.js b/services/frontend/src/common/index.js index e5a6bc2012..2fc3782fa1 100644 --- a/services/frontend/src/common/index.js +++ b/services/frontend/src/common/index.js @@ -438,3 +438,12 @@ export const isDefaultServiceProvider = () => { } export const formatContent = content => content.replace(/\n +/g, '\n') + +export const getCalendarYears = years => { + return years.reduce((all, year) => { + if (year === 'Total') { + return all + } + return all.concat(Number(year.slice(0, 4))) + }, []) +} diff --git a/services/frontend/src/components/FacultyStatistics/FacultyProgrammeOverview/FacultyStudentDataTable.jsx b/services/frontend/src/components/FacultyStatistics/FacultyProgrammeOverview/FacultyStudentDataTable.jsx index 69fd3521a5..7da73f8b87 100644 --- a/services/frontend/src/components/FacultyStatistics/FacultyProgrammeOverview/FacultyStudentDataTable.jsx +++ b/services/frontend/src/components/FacultyStatistics/FacultyProgrammeOverview/FacultyStudentDataTable.jsx @@ -1,6 +1,7 @@ import { Fragment, useState } from 'react' import { Button, Icon, Label, Popup, Table } from 'semantic-ui-react' +import { getCalendarYears } from '@/common' import { useLanguage } from '@/components/LanguagePicker/useLanguage' import { PopulationLink } from '@/components/StudyProgramme/StudyTrackOverview/PopulationLink' import { Toggle } from '@/components/StudyProgramme/Toggle' @@ -105,12 +106,6 @@ export const FacultyStudentDataTable = ({ arrayToModify[yearIndex] = !yearsVisible[yearIndex] setVisible(arrayToModify) } - - const calendarYears = years.reduce((all, year) => { - if (year === 'Total') return all - return all.concat(Number(year.slice(0, 4))) - }, []) - return (
))} diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.jsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.tsx similarity index 84% rename from services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.jsx rename to services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.tsx index 3792c0575f..a4f689dab1 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.jsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.tsx @@ -9,8 +9,19 @@ exporting(ReactHighcharts.Highcharts) exportData(ReactHighcharts.Highcharts) accessibility(ReactHighcharts.Highcharts) -export const BarChart = ({ data, track }) => { - if (!data || !data.creditGraphStats || !data.creditGraphStats[track]) return null +interface BarChartProps { + data: { + creditGraphStats: Record + years: string[] + } + track: string +} + +export const BarChart = ({ data, track }: BarChartProps) => { + if (!data || !data.creditGraphStats || !data.creditGraphStats[track]) { + return null + } + const correctData = data.creditGraphStats[track] const colors = generateGradientColors(correctData.length) const dataWithColors = Object.values(correctData).map((series, index) => ({ ...series, color: colors[index] })) diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.jsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx similarity index 62% rename from services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.jsx rename to services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx index a6ebd30ce4..6e74aa6b10 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.jsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx @@ -1,14 +1,20 @@ import { Table } from 'semantic-ui-react' -export const BasicDataTable = ({ data, titles, track }) => { +interface BasicDataTableProps { + data: Record>> + titles: string[] + track: string +} + +export const BasicDataTable = ({ data, titles, track }: BasicDataTableProps) => { if (!data || !data[track]?.length || !titles) { return null } - const sortedData = data[track].toSorted((a, b) => { + const sortedData = [...data[track]].sort((a, b) => { if (a[0] === 'Total') return 1 if (b[0] === 'Total') return -1 - return parseInt(b[0].split(' - ')[0], 10) - parseInt(a[0].split(' - ')[0], 10) + return parseInt(String(b[0]).split(' - ')[0], 10) - parseInt(String(a[0]).split(' - ')[0], 10) }) return ( @@ -23,11 +29,11 @@ export const BasicDataTable = ({ data, titles, track }) => { - {sortedData.map(array => ( - - {array.map((value, index) => ( + {sortedData.map(row => ( + + {row.map((value, index) => ( { - const end = moment() - const lastDayOfMonth = moment(end).endOf('month') - const start = `${year}-08-01` - return Math.round(moment.duration(moment(lastDayOfMonth).diff(moment(start))).asMonths()) -} - -const getTotalPopulationLink = (combinedProgramme, months, studyprogramme, studytrack, yearsString) => { - if (studytrack) { - return ( - `/populations?months=${months}&semesters=FALL&semesters=` + - `SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%2C"studyTrack"%3A"${studytrack}"%7D&year=All&years=${yearsString}` - ) - } - if (combinedProgramme) { - return ( - `/populations?months=${months}&semesters=FALL&semesters=` + - `SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%2C"combinedProgramme"%3A"${combinedProgramme}"%7D&year=All&years=${yearsString}` - ) - } - return ( - `/populations?months=${months}&semesters=FALL&semesters=` + - `SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%7D&year=All&years=${yearsString}` - ) -} - -const getPopulationLink = (combinedProgramme, months, startYear, studyprogramme, studytrack) => { - if (studytrack) { - return ( - `/populations?months=${months}&semesters=FALL&semesters=` + - `SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%2C"studyTrack"%3A"${studytrack}"%7D&year=${startYear}` - ) - } - if (combinedProgramme) { - return ( - `/populations?months=${months}&semesters=FALL&semesters=` + - `SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%2C"combinedProgramme"%3A"${combinedProgramme}"%7D&year=${startYear}` - ) - } - return ( - `/populations?months=${months}&semesters=FALL&semesters=` + - `SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%7D&year=${startYear}` - ) -} - -const PopulationStatisticsLink = ({ combinedProgramme, studyprogramme, studytrack, year }) => { - const startYear = Number(year.slice(0, 4)) - const months = Math.ceil(moment.duration(moment().diff(`${startYear}-08-01`)).asMonths()) - const href = getPopulationLink(combinedProgramme, months, startYear, studyprogramme, studytrack) - return ( - - - - ) -} - -const TotalPopulationLink = ({ combinedProgramme, studyprogramme, studytrack, years }) => { - const yearsString = years.join('&years=') - const months = getMonths(Math.min(...years.map(year => Number(year)))) - const href = getTotalPopulationLink(combinedProgramme, months, studyprogramme, studytrack, yearsString) - return ( - - - - ) -} - -export const PopulationLink = ({ year, ...rest }) => { - if (year === 'Total') { - return - } - return -} diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/PopulationLink.tsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/PopulationLink.tsx new file mode 100644 index 0000000000..54f867e90b --- /dev/null +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/PopulationLink.tsx @@ -0,0 +1,131 @@ +import moment from 'moment' +import { Link } from 'react-router-dom' +import { Icon } from 'semantic-ui-react' + +const getMonths = (year: number) => { + const end = moment() + const lastDayOfMonth = moment(end).endOf('month') + const start = `${year}-08-01` + return Math.round(moment.duration(moment(lastDayOfMonth).diff(moment(start))).asMonths()) +} + +const getTotalPopulationLink = ( + combinedProgramme: string | undefined, + months: number, + studyProgramme: string, + studyTrack: string | undefined, + years: string +) => { + if (studyTrack) { + return ( + `/populations?months=${months}&semesters=FALL&semesters=` + + `SPRING&studyRights=%7B"programme"%3A"${studyProgramme}"%2C"studyTrack"%3A"${studyTrack}"%7D&year=All&years=${years}` + ) + } + if (combinedProgramme) { + return ( + `/populations?months=${months}&semesters=FALL&semesters=` + + `SPRING&studyRights=%7B"programme"%3A"${studyProgramme}"%2C"combinedProgramme"%3A"${combinedProgramme}"%7D&year=All&years=${years}` + ) + } + return ( + `/populations?months=${months}&semesters=FALL&semesters=` + + `SPRING&studyRights=%7B"programme"%3A"${studyProgramme}"%7D&year=All&years=${years}` + ) +} + +const getPopulationLink = ( + combinedProgramme: string | undefined, + months: number, + startYear: number, + studyProgramme: string, + studyTrack: string | undefined +) => { + if (studyTrack) { + return ( + `/populations?months=${months}&semesters=FALL&semesters=` + + `SPRING&studyRights=%7B"programme"%3A"${studyProgramme}"%2C"studyTrack"%3A"${studyTrack}"%7D&year=${startYear}` + ) + } + if (combinedProgramme) { + return ( + `/populations?months=${months}&semesters=FALL&semesters=` + + `SPRING&studyRights=%7B"programme"%3A"${studyProgramme}"%2C"combinedProgramme"%3A"${combinedProgramme}"%7D&year=${startYear}` + ) + } + return ( + `/populations?months=${months}&semesters=FALL&semesters=` + + `SPRING&studyRights=%7B"programme"%3A"${studyProgramme}"%7D&year=${startYear}` + ) +} + +interface PopulationStatisticsLinkProps { + combinedProgramme: string | undefined + studyProgramme: string + studyTrack: string | undefined + year: string +} + +const PopulationStatisticsLink = ({ + combinedProgramme, + studyProgramme, + studyTrack, + year, +}: PopulationStatisticsLinkProps) => { + const startYear = Number(year.slice(0, 4)) + const months = Math.ceil(moment.duration(moment().diff(`${startYear}-08-01`)).asMonths()) + const href = getPopulationLink(combinedProgramme, months, startYear, studyProgramme, studyTrack) + return ( + + + + ) +} + +interface TotalPopulationLinkProps { + combinedProgramme?: string + studyProgramme: string + studyTrack?: string + years: number[] +} + +const TotalPopulationLink = ({ combinedProgramme, studyProgramme, studyTrack, years }: TotalPopulationLinkProps) => { + const yearsString = years.join('&years=') + const months = getMonths(Math.min(...years.map(year => Number(year)))) + const href = getTotalPopulationLink(combinedProgramme, months, studyProgramme, studyTrack, yearsString) + return ( + + + + ) +} + +interface PopulationLinkProps { + combinedProgramme?: string + studyProgramme: string + studyTrack?: string + year: string + years: number[] +} + +export const PopulationLink = ({ combinedProgramme, studyProgramme, studyTrack, year, years }: PopulationLinkProps) => { + if (year === 'Total') { + return ( + + ) + } + + return ( + + ) +} diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackDataTable.jsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackDataTable.jsx index 18253360c4..4a66276e99 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackDataTable.jsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackDataTable.jsx @@ -1,6 +1,7 @@ import { useState } from 'react' import { Icon, Popup, Table } from 'semantic-ui-react' +import { getCalendarYears } from '@/common' import { useLanguage } from '@/components/LanguagePicker/useLanguage' import { Toggle } from '@/components/StudyProgramme/Toggle' import { useGetAuthorizedUserQuery } from '@/redux/auth' @@ -83,7 +84,7 @@ const getFirstCell = ({ {(fullAccessToStudentData || allRights.includes(studyProgramme) || allRights.includes(combinedProgramme)) && ( @@ -130,8 +131,8 @@ const getSingleTrackRow = ({ allRights.includes(combinedProgramme)) && ( @@ -198,11 +199,11 @@ const getRow = ({ return null } - const correctStudytrack = row[0] + const correctStudyTrack = row[0] const title = - studyTracks[correctStudytrack] === undefined - ? correctStudytrack - : `${getTextIn(studyTracks[correctStudytrack])}, ${correctStudytrack}` + studyTracks[correctStudyTrack] === undefined + ? correctStudyTrack + : `${getTextIn(studyTracks[correctStudyTrack])}, ${correctStudyTrack}` return ( @@ -218,8 +219,8 @@ const getRow = ({ allRights.includes(combinedProgramme)) && ( @@ -233,7 +234,7 @@ const getRow = ({ index, otherCountriesStats, row, - studyprogramme: correctStudytrack, + studyProgramme: correctStudyTrack, value, year, }) @@ -306,10 +307,7 @@ export const StudyTrackDataTable = ({ } const sortedMainStats = sortMainDataByYear(Object.values(dataOfAllTracks)) const sortedTrackStats = sortTrackDataByYear(dataOfSingleTrack) - const calendarYears = years.reduce((all, year) => { - if (year === 'Total') return all - return all.concat(Number(year.slice(0, 4))) - }, []) + const calendarYears = getCalendarYears(years) const borderStyleArray = combinedProgramme ? [3, 8, 11] : [3, 7, 10] return (
diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackSelector.jsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackSelector.tsx similarity index 55% rename from services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackSelector.jsx rename to services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackSelector.tsx index 41f2426c24..3ea93cdc6e 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackSelector.jsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackSelector.tsx @@ -1,31 +1,39 @@ -import { Dropdown } from 'semantic-ui-react' +import { Dropdown, DropdownProps } from 'semantic-ui-react' import '../studyprogramme.css' import { useLanguage } from '@/components/LanguagePicker/useLanguage' +import { Name } from '@/shared/types' -export const StudyTrackSelector = ({ track, setTrack, studyTracks }) => { +interface StudyTrackSelectorProps { + track: string + setTrack: (track: string) => void + studyTracks: Record +} + +export const StudyTrackSelector = ({ track, setTrack, studyTracks }: StudyTrackSelectorProps) => { const { getTextIn } = useLanguage() if (!studyTracks) { return null } - const handleStudytrackChange = (event, { value }) => { + const handleStudyTrackChange = (event: React.SyntheticEvent, data: DropdownProps) => { + const { value } = data event.preventDefault() - setTrack(value) + setTrack(value as string) } - const getOptionName = track => { - if (track !== 'All students of the programme') { - return getTextIn(track) + const getOptionName = (studyTrack: string | Name) => { + if (studyTrack !== 'All students of the programme') { + return getTextIn(studyTrack) } - return track + return studyTrack } const studyTrackOptions = Object.entries(studyTracks) - .map(([code, track]) => ({ + .map(([code, studyTrack]) => ({ key: code, value: code, - text: `${getOptionName(track)}, ${code}`, + text: `${getOptionName(studyTrack)}, ${code}`, })) .sort((a, b) => { if (a.text.startsWith('All students of the programme')) return -1 @@ -39,7 +47,7 @@ export const StudyTrackSelector = ({ track, setTrack, studyTracks }) => { Date: Tue, 5 Nov 2024 12:55:33 +0200 Subject: [PATCH 05/13] [Graduation times] Display percentages only for bachelor study rights --- .../FacultyStatistics/TimesAndPaths/GraduationTimes.jsx | 4 ++++ .../FacultyStatistics/TimesAndPaths/MedianBarChart.jsx | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/services/frontend/src/components/FacultyStatistics/TimesAndPaths/GraduationTimes.jsx b/services/frontend/src/components/FacultyStatistics/TimesAndPaths/GraduationTimes.jsx index 79c0a3039a..d78449c989 100644 --- a/services/frontend/src/components/FacultyStatistics/TimesAndPaths/GraduationTimes.jsx +++ b/services/frontend/src/components/FacultyStatistics/TimesAndPaths/GraduationTimes.jsx @@ -17,6 +17,7 @@ const MedianDisplay = ({ mode, programmeData, programmeNames, + title, year, yearLabel, }) => { @@ -46,6 +47,7 @@ const MedianDisplay = ({ handleClick={handleClick} mode={mode} programmeNames={programmeNames} + title={title} yearLabel={yearLabel} /> {!programmeData || !(year in levelProgrammeData) ? ( @@ -63,6 +65,7 @@ const MedianDisplay = ({ level={level} mode={mode} programmeNames={programmeNames} + title={title} year={year} yearLabel={yearLabel} /> @@ -163,6 +166,7 @@ export const GraduationTimes = ({ mode={mode} programmeData={programmeData} programmeNames={programmeNames} + title={title} year={year} yearLabel={yearLabel} /> diff --git a/services/frontend/src/components/FacultyStatistics/TimesAndPaths/MedianBarChart.jsx b/services/frontend/src/components/FacultyStatistics/TimesAndPaths/MedianBarChart.jsx index 5334f9ca1f..9d11901736 100644 --- a/services/frontend/src/components/FacultyStatistics/TimesAndPaths/MedianBarChart.jsx +++ b/services/frontend/src/components/FacultyStatistics/TimesAndPaths/MedianBarChart.jsx @@ -19,6 +19,7 @@ export const MedianBarChart = ({ level, mode, programmeNames, + title, year, yearLabel, }) => { @@ -56,7 +57,7 @@ export const MedianBarChart = ({ } const getDataLabel = (amount, category) => { - if (yearLabel === 'Start year') { + if (yearLabel === 'Start year' && title === 'Bachelor study right') { return `${amount} graduated (${getPercentage(amount, category)} % of class)` } return `${amount} graduated` @@ -203,7 +204,9 @@ export const MedianBarChart = ({ }, } - if (!facultyGraph) config.title.text = `Year ${year} by ${yearLabel.toLowerCase()}` + if (!facultyGraph) { + config.title.text = `Year ${year} by ${yearLabel.toLowerCase()}` + } return (
From 6468aaff872392ac32fe63e09fba7be49970749e Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 5 Nov 2024 10:00:41 +0200 Subject: [PATCH 06/13] [SegmentDimmer] Convert to TypeScript --- .../src/components/SegmentDimmer/{index.jsx => index.tsx} | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) rename services/frontend/src/components/SegmentDimmer/{index.jsx => index.tsx} (50%) diff --git a/services/frontend/src/components/SegmentDimmer/index.jsx b/services/frontend/src/components/SegmentDimmer/index.tsx similarity index 50% rename from services/frontend/src/components/SegmentDimmer/index.jsx rename to services/frontend/src/components/SegmentDimmer/index.tsx index 904c60e882..b2286d6ab4 100644 --- a/services/frontend/src/components/SegmentDimmer/index.jsx +++ b/services/frontend/src/components/SegmentDimmer/index.tsx @@ -1,6 +1,10 @@ import { Dimmer, Loader } from 'semantic-ui-react' -export const SegmentDimmer = ({ isLoading = false }) => ( +interface SegmentDimmerProps { + isLoading?: boolean +} + +export const SegmentDimmer = ({ isLoading = false }: SegmentDimmerProps) => ( Loading From 44d15b5ed8909638c3e6513c8d7d894abf4c355a Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 5 Nov 2024 10:01:47 +0200 Subject: [PATCH 07/13] [facultyHelpers] Convert to TypeScript --- .../{facultyHelpers.js => facultyHelpers.ts} | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) rename services/frontend/src/components/FacultyStatistics/{facultyHelpers.js => facultyHelpers.ts} (93%) diff --git a/services/frontend/src/components/FacultyStatistics/facultyHelpers.js b/services/frontend/src/components/FacultyStatistics/facultyHelpers.ts similarity index 93% rename from services/frontend/src/components/FacultyStatistics/facultyHelpers.js rename to services/frontend/src/components/FacultyStatistics/facultyHelpers.ts index 0f77084a19..f310b87afd 100644 --- a/services/frontend/src/components/FacultyStatistics/facultyHelpers.js +++ b/services/frontend/src/components/FacultyStatistics/facultyHelpers.ts @@ -18,9 +18,9 @@ const regexValuesAll = [ /^Y/, /\d$/, /^\d.*e$/, -] +] as const -const testKey = value => { +const testKey = (value: string) => { for (let i = 0; i < regexValuesAll.length; i++) { if (regexValuesAll[i].test(value)) { return i @@ -29,7 +29,7 @@ const testKey = value => { return 6 } -export const sortProgrammeKeys = (programmeKeys, faculty) => { +export const sortProgrammeKeys = (programmeKeys: string[][], faculty: string) => { try { return programmeKeys.sort((a, b) => { if (a[1].includes(faculty) && !b[1].includes(faculty)) return -1 @@ -38,9 +38,7 @@ export const sortProgrammeKeys = (programmeKeys, faculty) => { if (!a[1].includes(faculty) && b[1].startsWith('T') && !a[1].includes('T')) return 1 if (a[1].startsWith('LIS') && !b[1].includes(faculty) && !b[1].includes('LIS')) return -1 if (!a[1].includes(faculty) && b[1].startsWith('LIS') && !a[1].includes('LIS')) return 1 - if (testKey(a[1]) - testKey(b[1]) === 0) { - return a[0].localeCompare(b[0]) - } + if (testKey(a[1]) - testKey(b[1]) === 0) return a[0].localeCompare(b[0]) return testKey(a[1]) - testKey(b[1]) }) } catch (error) { From b2a92d9003c7988c4a7f2f3d97cc4300e71847f1 Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 5 Nov 2024 10:26:52 +0200 Subject: [PATCH 08/13] [ProgressOfStudents] Convert to TypeScript --- ...gressOfStudents.jsx => ProgressOfStudents.tsx} | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) rename services/frontend/src/components/StudyProgramme/StudyTrackOverview/{ProgressOfStudents.jsx => ProgressOfStudents.tsx} (84%) diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents.jsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents.tsx similarity index 84% rename from services/frontend/src/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents.jsx rename to services/frontend/src/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents.tsx index f035289378..ba7714a67c 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents.jsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents.tsx @@ -1,7 +1,20 @@ import { BarChart } from './BarChart' import { BasicDataTable } from './BasicDataTable' -export const ProgressOfStudents = ({ progressStats, progressComboStats, track, years }) => { +interface ProgressStats { + chartStats: Array<{ data: number[]; name: string }> + tableStats: Array> + tableTitles: string[] +} + +interface ProgressOfStudentsProps { + progressStats: ProgressStats + progressComboStats: ProgressStats + track: string + years: string[] +} + +export const ProgressOfStudents = ({ progressStats, progressComboStats, track, years }: ProgressOfStudentsProps) => { return (
{progressComboStats != null && ( From 8c05c1c2f365f1f493a9c60edc7a40a5e4e7e2b4 Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 5 Nov 2024 11:32:15 +0200 Subject: [PATCH 09/13] [StudyTrackOverview] Convert most components to TypeScript --- services/frontend/src/common/index.js | 9 ++ .../FacultyStudentDataTable.jsx | 11 +- .../{BarChart.jsx => BarChart.tsx} | 15 +- ...{BasicDataTable.jsx => BasicDataTable.tsx} | 20 ++- .../StudyTrackOverview/PopulationLink.jsx | 77 ---------- .../StudyTrackOverview/PopulationLink.tsx | 131 ++++++++++++++++++ .../StudyTrackDataTable.jsx | 26 ++-- ...ackSelector.jsx => StudyTrackSelector.tsx} | 30 ++-- 8 files changed, 200 insertions(+), 119 deletions(-) rename services/frontend/src/components/StudyProgramme/StudyTrackOverview/{BarChart.jsx => BarChart.tsx} (84%) rename services/frontend/src/components/StudyProgramme/StudyTrackOverview/{BasicDataTable.jsx => BasicDataTable.tsx} (62%) delete mode 100644 services/frontend/src/components/StudyProgramme/StudyTrackOverview/PopulationLink.jsx create mode 100644 services/frontend/src/components/StudyProgramme/StudyTrackOverview/PopulationLink.tsx rename services/frontend/src/components/StudyProgramme/StudyTrackOverview/{StudyTrackSelector.jsx => StudyTrackSelector.tsx} (55%) diff --git a/services/frontend/src/common/index.js b/services/frontend/src/common/index.js index e5a6bc2012..2fc3782fa1 100644 --- a/services/frontend/src/common/index.js +++ b/services/frontend/src/common/index.js @@ -438,3 +438,12 @@ export const isDefaultServiceProvider = () => { } export const formatContent = content => content.replace(/\n +/g, '\n') + +export const getCalendarYears = years => { + return years.reduce((all, year) => { + if (year === 'Total') { + return all + } + return all.concat(Number(year.slice(0, 4))) + }, []) +} diff --git a/services/frontend/src/components/FacultyStatistics/FacultyProgrammeOverview/FacultyStudentDataTable.jsx b/services/frontend/src/components/FacultyStatistics/FacultyProgrammeOverview/FacultyStudentDataTable.jsx index 69fd3521a5..7da73f8b87 100644 --- a/services/frontend/src/components/FacultyStatistics/FacultyProgrammeOverview/FacultyStudentDataTable.jsx +++ b/services/frontend/src/components/FacultyStatistics/FacultyProgrammeOverview/FacultyStudentDataTable.jsx @@ -1,6 +1,7 @@ import { Fragment, useState } from 'react' import { Button, Icon, Label, Popup, Table } from 'semantic-ui-react' +import { getCalendarYears } from '@/common' import { useLanguage } from '@/components/LanguagePicker/useLanguage' import { PopulationLink } from '@/components/StudyProgramme/StudyTrackOverview/PopulationLink' import { Toggle } from '@/components/StudyProgramme/Toggle' @@ -105,12 +106,6 @@ export const FacultyStudentDataTable = ({ arrayToModify[yearIndex] = !yearsVisible[yearIndex] setVisible(arrayToModify) } - - const calendarYears = years.reduce((all, year) => { - if (year === 'Total') return all - return all.concat(Number(year.slice(0, 4))) - }, []) - return (
))} diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.jsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.tsx similarity index 84% rename from services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.jsx rename to services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.tsx index 3792c0575f..a4f689dab1 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.jsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.tsx @@ -9,8 +9,19 @@ exporting(ReactHighcharts.Highcharts) exportData(ReactHighcharts.Highcharts) accessibility(ReactHighcharts.Highcharts) -export const BarChart = ({ data, track }) => { - if (!data || !data.creditGraphStats || !data.creditGraphStats[track]) return null +interface BarChartProps { + data: { + creditGraphStats: Record + years: string[] + } + track: string +} + +export const BarChart = ({ data, track }: BarChartProps) => { + if (!data || !data.creditGraphStats || !data.creditGraphStats[track]) { + return null + } + const correctData = data.creditGraphStats[track] const colors = generateGradientColors(correctData.length) const dataWithColors = Object.values(correctData).map((series, index) => ({ ...series, color: colors[index] })) diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.jsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx similarity index 62% rename from services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.jsx rename to services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx index a6ebd30ce4..6e74aa6b10 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.jsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx @@ -1,14 +1,20 @@ import { Table } from 'semantic-ui-react' -export const BasicDataTable = ({ data, titles, track }) => { +interface BasicDataTableProps { + data: Record>> + titles: string[] + track: string +} + +export const BasicDataTable = ({ data, titles, track }: BasicDataTableProps) => { if (!data || !data[track]?.length || !titles) { return null } - const sortedData = data[track].toSorted((a, b) => { + const sortedData = [...data[track]].sort((a, b) => { if (a[0] === 'Total') return 1 if (b[0] === 'Total') return -1 - return parseInt(b[0].split(' - ')[0], 10) - parseInt(a[0].split(' - ')[0], 10) + return parseInt(String(b[0]).split(' - ')[0], 10) - parseInt(String(a[0]).split(' - ')[0], 10) }) return ( @@ -23,11 +29,11 @@ export const BasicDataTable = ({ data, titles, track }) => { - {sortedData.map(array => ( - - {array.map((value, index) => ( + {sortedData.map(row => ( + + {row.map((value, index) => ( { - const end = moment() - const lastDayOfMonth = moment(end).endOf('month') - const start = `${year}-08-01` - return Math.round(moment.duration(moment(lastDayOfMonth).diff(moment(start))).asMonths()) -} - -const getTotalPopulationLink = (combinedProgramme, months, studyprogramme, studytrack, yearsString) => { - if (studytrack) { - return ( - `/populations?months=${months}&semesters=FALL&semesters=` + - `SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%2C"studyTrack"%3A"${studytrack}"%7D&year=All&years=${yearsString}` - ) - } - if (combinedProgramme) { - return ( - `/populations?months=${months}&semesters=FALL&semesters=` + - `SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%2C"combinedProgramme"%3A"${combinedProgramme}"%7D&year=All&years=${yearsString}` - ) - } - return ( - `/populations?months=${months}&semesters=FALL&semesters=` + - `SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%7D&year=All&years=${yearsString}` - ) -} - -const getPopulationLink = (combinedProgramme, months, startYear, studyprogramme, studytrack) => { - if (studytrack) { - return ( - `/populations?months=${months}&semesters=FALL&semesters=` + - `SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%2C"studyTrack"%3A"${studytrack}"%7D&year=${startYear}` - ) - } - if (combinedProgramme) { - return ( - `/populations?months=${months}&semesters=FALL&semesters=` + - `SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%2C"combinedProgramme"%3A"${combinedProgramme}"%7D&year=${startYear}` - ) - } - return ( - `/populations?months=${months}&semesters=FALL&semesters=` + - `SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%7D&year=${startYear}` - ) -} - -const PopulationStatisticsLink = ({ combinedProgramme, studyprogramme, studytrack, year }) => { - const startYear = Number(year.slice(0, 4)) - const months = Math.ceil(moment.duration(moment().diff(`${startYear}-08-01`)).asMonths()) - const href = getPopulationLink(combinedProgramme, months, startYear, studyprogramme, studytrack) - return ( - - - - ) -} - -const TotalPopulationLink = ({ combinedProgramme, studyprogramme, studytrack, years }) => { - const yearsString = years.join('&years=') - const months = getMonths(Math.min(...years.map(year => Number(year)))) - const href = getTotalPopulationLink(combinedProgramme, months, studyprogramme, studytrack, yearsString) - return ( - - - - ) -} - -export const PopulationLink = ({ year, ...rest }) => { - if (year === 'Total') { - return - } - return -} diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/PopulationLink.tsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/PopulationLink.tsx new file mode 100644 index 0000000000..54f867e90b --- /dev/null +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/PopulationLink.tsx @@ -0,0 +1,131 @@ +import moment from 'moment' +import { Link } from 'react-router-dom' +import { Icon } from 'semantic-ui-react' + +const getMonths = (year: number) => { + const end = moment() + const lastDayOfMonth = moment(end).endOf('month') + const start = `${year}-08-01` + return Math.round(moment.duration(moment(lastDayOfMonth).diff(moment(start))).asMonths()) +} + +const getTotalPopulationLink = ( + combinedProgramme: string | undefined, + months: number, + studyProgramme: string, + studyTrack: string | undefined, + years: string +) => { + if (studyTrack) { + return ( + `/populations?months=${months}&semesters=FALL&semesters=` + + `SPRING&studyRights=%7B"programme"%3A"${studyProgramme}"%2C"studyTrack"%3A"${studyTrack}"%7D&year=All&years=${years}` + ) + } + if (combinedProgramme) { + return ( + `/populations?months=${months}&semesters=FALL&semesters=` + + `SPRING&studyRights=%7B"programme"%3A"${studyProgramme}"%2C"combinedProgramme"%3A"${combinedProgramme}"%7D&year=All&years=${years}` + ) + } + return ( + `/populations?months=${months}&semesters=FALL&semesters=` + + `SPRING&studyRights=%7B"programme"%3A"${studyProgramme}"%7D&year=All&years=${years}` + ) +} + +const getPopulationLink = ( + combinedProgramme: string | undefined, + months: number, + startYear: number, + studyProgramme: string, + studyTrack: string | undefined +) => { + if (studyTrack) { + return ( + `/populations?months=${months}&semesters=FALL&semesters=` + + `SPRING&studyRights=%7B"programme"%3A"${studyProgramme}"%2C"studyTrack"%3A"${studyTrack}"%7D&year=${startYear}` + ) + } + if (combinedProgramme) { + return ( + `/populations?months=${months}&semesters=FALL&semesters=` + + `SPRING&studyRights=%7B"programme"%3A"${studyProgramme}"%2C"combinedProgramme"%3A"${combinedProgramme}"%7D&year=${startYear}` + ) + } + return ( + `/populations?months=${months}&semesters=FALL&semesters=` + + `SPRING&studyRights=%7B"programme"%3A"${studyProgramme}"%7D&year=${startYear}` + ) +} + +interface PopulationStatisticsLinkProps { + combinedProgramme: string | undefined + studyProgramme: string + studyTrack: string | undefined + year: string +} + +const PopulationStatisticsLink = ({ + combinedProgramme, + studyProgramme, + studyTrack, + year, +}: PopulationStatisticsLinkProps) => { + const startYear = Number(year.slice(0, 4)) + const months = Math.ceil(moment.duration(moment().diff(`${startYear}-08-01`)).asMonths()) + const href = getPopulationLink(combinedProgramme, months, startYear, studyProgramme, studyTrack) + return ( + + + + ) +} + +interface TotalPopulationLinkProps { + combinedProgramme?: string + studyProgramme: string + studyTrack?: string + years: number[] +} + +const TotalPopulationLink = ({ combinedProgramme, studyProgramme, studyTrack, years }: TotalPopulationLinkProps) => { + const yearsString = years.join('&years=') + const months = getMonths(Math.min(...years.map(year => Number(year)))) + const href = getTotalPopulationLink(combinedProgramme, months, studyProgramme, studyTrack, yearsString) + return ( + + + + ) +} + +interface PopulationLinkProps { + combinedProgramme?: string + studyProgramme: string + studyTrack?: string + year: string + years: number[] +} + +export const PopulationLink = ({ combinedProgramme, studyProgramme, studyTrack, year, years }: PopulationLinkProps) => { + if (year === 'Total') { + return ( + + ) + } + + return ( + + ) +} diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackDataTable.jsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackDataTable.jsx index 18253360c4..4a66276e99 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackDataTable.jsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackDataTable.jsx @@ -1,6 +1,7 @@ import { useState } from 'react' import { Icon, Popup, Table } from 'semantic-ui-react' +import { getCalendarYears } from '@/common' import { useLanguage } from '@/components/LanguagePicker/useLanguage' import { Toggle } from '@/components/StudyProgramme/Toggle' import { useGetAuthorizedUserQuery } from '@/redux/auth' @@ -83,7 +84,7 @@ const getFirstCell = ({ {(fullAccessToStudentData || allRights.includes(studyProgramme) || allRights.includes(combinedProgramme)) && ( @@ -130,8 +131,8 @@ const getSingleTrackRow = ({ allRights.includes(combinedProgramme)) && ( @@ -198,11 +199,11 @@ const getRow = ({ return null } - const correctStudytrack = row[0] + const correctStudyTrack = row[0] const title = - studyTracks[correctStudytrack] === undefined - ? correctStudytrack - : `${getTextIn(studyTracks[correctStudytrack])}, ${correctStudytrack}` + studyTracks[correctStudyTrack] === undefined + ? correctStudyTrack + : `${getTextIn(studyTracks[correctStudyTrack])}, ${correctStudyTrack}` return ( @@ -218,8 +219,8 @@ const getRow = ({ allRights.includes(combinedProgramme)) && ( @@ -233,7 +234,7 @@ const getRow = ({ index, otherCountriesStats, row, - studyprogramme: correctStudytrack, + studyProgramme: correctStudyTrack, value, year, }) @@ -306,10 +307,7 @@ export const StudyTrackDataTable = ({ } const sortedMainStats = sortMainDataByYear(Object.values(dataOfAllTracks)) const sortedTrackStats = sortTrackDataByYear(dataOfSingleTrack) - const calendarYears = years.reduce((all, year) => { - if (year === 'Total') return all - return all.concat(Number(year.slice(0, 4))) - }, []) + const calendarYears = getCalendarYears(years) const borderStyleArray = combinedProgramme ? [3, 8, 11] : [3, 7, 10] return (
diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackSelector.jsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackSelector.tsx similarity index 55% rename from services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackSelector.jsx rename to services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackSelector.tsx index 41f2426c24..3ea93cdc6e 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackSelector.jsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/StudyTrackSelector.tsx @@ -1,31 +1,39 @@ -import { Dropdown } from 'semantic-ui-react' +import { Dropdown, DropdownProps } from 'semantic-ui-react' import '../studyprogramme.css' import { useLanguage } from '@/components/LanguagePicker/useLanguage' +import { Name } from '@/shared/types' -export const StudyTrackSelector = ({ track, setTrack, studyTracks }) => { +interface StudyTrackSelectorProps { + track: string + setTrack: (track: string) => void + studyTracks: Record +} + +export const StudyTrackSelector = ({ track, setTrack, studyTracks }: StudyTrackSelectorProps) => { const { getTextIn } = useLanguage() if (!studyTracks) { return null } - const handleStudytrackChange = (event, { value }) => { + const handleStudyTrackChange = (event: React.SyntheticEvent, data: DropdownProps) => { + const { value } = data event.preventDefault() - setTrack(value) + setTrack(value as string) } - const getOptionName = track => { - if (track !== 'All students of the programme') { - return getTextIn(track) + const getOptionName = (studyTrack: string | Name) => { + if (studyTrack !== 'All students of the programme') { + return getTextIn(studyTrack) } - return track + return studyTrack } const studyTrackOptions = Object.entries(studyTracks) - .map(([code, track]) => ({ + .map(([code, studyTrack]) => ({ key: code, value: code, - text: `${getOptionName(track)}, ${code}`, + text: `${getOptionName(studyTrack)}, ${code}`, })) .sort((a, b) => { if (a.text.startsWith('All students of the programme')) return -1 @@ -39,7 +47,7 @@ export const StudyTrackSelector = ({ track, setTrack, studyTracks }) => { Date: Tue, 5 Nov 2024 12:55:33 +0200 Subject: [PATCH 10/13] [Graduation times] Display percentages only for bachelor study rights --- .../FacultyStatistics/TimesAndPaths/GraduationTimes.jsx | 4 ++++ .../FacultyStatistics/TimesAndPaths/MedianBarChart.jsx | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/services/frontend/src/components/FacultyStatistics/TimesAndPaths/GraduationTimes.jsx b/services/frontend/src/components/FacultyStatistics/TimesAndPaths/GraduationTimes.jsx index 79c0a3039a..d78449c989 100644 --- a/services/frontend/src/components/FacultyStatistics/TimesAndPaths/GraduationTimes.jsx +++ b/services/frontend/src/components/FacultyStatistics/TimesAndPaths/GraduationTimes.jsx @@ -17,6 +17,7 @@ const MedianDisplay = ({ mode, programmeData, programmeNames, + title, year, yearLabel, }) => { @@ -46,6 +47,7 @@ const MedianDisplay = ({ handleClick={handleClick} mode={mode} programmeNames={programmeNames} + title={title} yearLabel={yearLabel} /> {!programmeData || !(year in levelProgrammeData) ? ( @@ -63,6 +65,7 @@ const MedianDisplay = ({ level={level} mode={mode} programmeNames={programmeNames} + title={title} year={year} yearLabel={yearLabel} /> @@ -163,6 +166,7 @@ export const GraduationTimes = ({ mode={mode} programmeData={programmeData} programmeNames={programmeNames} + title={title} year={year} yearLabel={yearLabel} /> diff --git a/services/frontend/src/components/FacultyStatistics/TimesAndPaths/MedianBarChart.jsx b/services/frontend/src/components/FacultyStatistics/TimesAndPaths/MedianBarChart.jsx index 5334f9ca1f..9d11901736 100644 --- a/services/frontend/src/components/FacultyStatistics/TimesAndPaths/MedianBarChart.jsx +++ b/services/frontend/src/components/FacultyStatistics/TimesAndPaths/MedianBarChart.jsx @@ -19,6 +19,7 @@ export const MedianBarChart = ({ level, mode, programmeNames, + title, year, yearLabel, }) => { @@ -56,7 +57,7 @@ export const MedianBarChart = ({ } const getDataLabel = (amount, category) => { - if (yearLabel === 'Start year') { + if (yearLabel === 'Start year' && title === 'Bachelor study right') { return `${amount} graduated (${getPercentage(amount, category)} % of class)` } return `${amount} graduated` @@ -203,7 +204,9 @@ export const MedianBarChart = ({ }, } - if (!facultyGraph) config.title.text = `Year ${year} by ${yearLabel.toLowerCase()}` + if (!facultyGraph) { + config.title.text = `Year ${year} by ${yearLabel.toLowerCase()}` + } return (
From ad6bd96af644828412c5c2c413ccc7d37122759a Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 5 Nov 2024 13:06:24 +0200 Subject: [PATCH 11/13] [TSConfig] Update ES2020 lib to ES2023 --- .../StudyProgramme/StudyTrackOverview/BasicDataTable.tsx | 2 +- services/frontend/tsconfig.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx index 6e74aa6b10..ef7b878747 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx @@ -11,7 +11,7 @@ export const BasicDataTable = ({ data, titles, track }: BasicDataTableProps) => return null } - const sortedData = [...data[track]].sort((a, b) => { + const sortedData = data[track].toSorted((a, b) => { if (a[0] === 'Total') return 1 if (b[0] === 'Total') return -1 return parseInt(String(b[0]).split(' - ')[0], 10) - parseInt(String(a[0]).split(' - ')[0], 10) diff --git a/services/frontend/tsconfig.json b/services/frontend/tsconfig.json index d90227ea6b..59c3b4bef4 100644 --- a/services/frontend/tsconfig.json +++ b/services/frontend/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "ES2020", "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2023", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true, From 62419f0fe4c7052b3775d81ce5c48200557d6eae Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 5 Nov 2024 13:13:46 +0200 Subject: [PATCH 12/13] [Faculties] Type new function calculateStats --- .../FacultyStatistics/facultyHelpers.ts | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/services/frontend/src/components/FacultyStatistics/facultyHelpers.ts b/services/frontend/src/components/FacultyStatistics/facultyHelpers.ts index f310b87afd..ad6e3993ee 100644 --- a/services/frontend/src/components/FacultyStatistics/facultyHelpers.ts +++ b/services/frontend/src/components/FacultyStatistics/facultyHelpers.ts @@ -46,20 +46,24 @@ export const sortProgrammeKeys = (programmeKeys: string[][], faculty: string) => } } -const isBetween = (number, lowerLimit, upperLimit) => { +const isBetween = (number: number, lowerLimit: number, upperLimit: number) => { return (lowerLimit === undefined || number >= lowerLimit) && (upperLimit === undefined || number < upperLimit) } export const calculateStats = ( - creditCounts, - maximumAmountOfCredits, - minimumAmountOfCredits = 0, - numberOfCreditCategories = 7 + creditCounts: Record, + maximumAmountOfCredits: number, + minimumAmountOfCredits: number = 0, + numberOfCreditCategories: number = 7 ) => { - const tableStats = [] - if (creditCounts === undefined) return null + const tableStats: Array> = [] + if (creditCounts === undefined) { + return null + } - if (Object.keys(creditCounts).length === 0) return null + if (Object.keys(creditCounts).length === 0) { + return null + } const limits = getCreditCategories( true, @@ -85,24 +89,25 @@ export const calculateStats = ( } }) - const totalCounts = ['Total'] + const totalCounts: Array = ['Total'] for (let i = 1; i < tableStats[0].length; i++) { let columnSum = 0 for (let j = 0; j < tableStats.length; j++) { - columnSum += tableStats[j][i] + columnSum += tableStats[j][i] as number } totalCounts.push(columnSum) } tableStats.push(totalCounts) // Calculate statistics for the bar chart (i.e., transpose the tableStats as rows are now columns and vice versa) - const chartStats = [] + const chartStats: Array<{ data: number[]; name: string }> = [] for (let i = 2; i < tableStats[0].length; i++) { - const column = [] + const column: number[] = [] for (let j = tableStats.length - 1; j >= 0; j--) { - column.push(tableStats[j][i]) + column.push(tableStats[j][i] as number) } chartStats.push({ name: tableTitles[i].replace('<', 'Less than').replace('≥', 'At least'), data: column }) } + return { tableStats, chartStats, tableTitles } } From fc426136257c37ed934c36602164e99078e109b4 Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 5 Nov 2024 13:23:37 +0200 Subject: [PATCH 13/13] [Faculties] Update tests --- cypress/e2e/Faculty_statistics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/e2e/Faculty_statistics.js b/cypress/e2e/Faculty_statistics.js index a73eb1a04a..fc1dc35feb 100644 --- a/cypress/e2e/Faculty_statistics.js +++ b/cypress/e2e/Faculty_statistics.js @@ -234,7 +234,7 @@ describe('Faculty overview', () => { cy.get('[data-cy="Section-bachelor"]').within(() => { cy.get('div[class="faculty-graph"]') - cy.contains('24 graduated (64.9 % of class)').trigger('mouseover') + cy.contains('24 graduated').trigger('mouseover') cy.contains('From class of 2020 - 2021, 24/37 students have graduated') })