Skip to content

Commit

Permalink
Merge pull request #4451 from UniversityOfHelsinkiCS/firefox-fix
Browse files Browse the repository at this point in the history
[Class statistics] Fix broken dates on Firefox
  • Loading branch information
valtterikantanen authored Mar 20, 2024
2 parents a94dcd2 + d63e69a commit 268fc7c
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 45 deletions.
14 changes: 11 additions & 3 deletions services/frontend/src/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,13 @@ export const containsOnlyNumbers = str => str.match('^\\d+$')

export const momentFromFormat = (date, format) => moment(date, format)

export const reformatDate = (date, outputFormat) => (!date ? 'Unavailable' : moment(date).local().format(outputFormat))
export const reformatDate = (date, outputFormat) => {
if (!date) {
return 'Unavailable'
}
const parsedDate = moment(date, 'YYYY-MM-DD').local().format(outputFormat)
return parsedDate
}

export const byDateDesc = (a, b) => new Date(b.date) - new Date(a.date)

Expand Down Expand Up @@ -257,15 +263,17 @@ export const getHighestGradeOrEnrollmentOfCourseBetweenRange = (courses, enrollm
return grade
}

export const findStudyrightElementForClass = (studyrights, programme, year) =>
studyrights
export const findStudyrightElementForClass = (studyrights, programme, year) => {
return studyrights
.flatMap(studyright => studyright.studyright_elements)
.find(element => {
if (element.code !== programme) return false
if (year === 'All') return true
const date = moment(new Date(`${year}-08-01`))
const endDate = moment(new Date(element.enddate))
return date.isBefore(endDate, undefined, '[]')
})
}

const getEarliestStudyRightElement = studyright => {
if (!studyright) return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ export const GeneralTab = ({
}, {})
}

const selectedStudents = filteredStudents.map(stu => stu.studentNumber)
const students = filteredStudents.reduce((acc, stu) => {
acc[stu.studentNumber] = columnKeysToInclude.includes('semesterEnrollments')
? { ...stu, semesterEnrollmentsMap: createSemesterEnrollmentsMap(stu) }
: stu
const selectedStudents = filteredStudents.map(student => student.studentNumber)
const students = filteredStudents.reduce((acc, student) => {
acc[student.studentNumber] = columnKeysToInclude.includes('semesterEnrollments')
? { ...student, semesterEnrollmentsMap: createSemesterEnrollmentsMap(student) }
: student
return acc
}, {})

Expand Down Expand Up @@ -240,8 +240,8 @@ export const GeneralTab = ({
const containsStudyTracks =
Object.keys(populationStatistics.elementdetails.data) > 0
? selectedStudents
.map(sn => students[sn])
.map(st => st.studyrights)
.map(studentNumber => students[studentNumber])
.map(student => student.studyrights)
.map(
studyrights =>
studyrightCodes(studyrights, 'studyright_elements').reduce((acc, elements) => {
Expand Down Expand Up @@ -290,7 +290,7 @@ export const GeneralTab = ({
}

let creditsColumn = null
const creditColumnKeys = columnKeysToInclude.filter(k => k.indexOf('credits.') === 0)
const creditColumnKeys = columnKeysToInclude.filter(key => key.indexOf('credits.') === 0)

const { getSemesterEnrollmentsContent, getSemesterEnrollmentsForExcel, getSemesterEnrollmentsVal } =
getSemestersPresentFunctions({
Expand Down Expand Up @@ -373,7 +373,6 @@ export const GeneralTab = ({
}
}

// All columns components user is able to use
const columnsAvailable = {
lastname: { key: 'lastname', title: 'Last name', getRowVal: student => student.lastname, export: false },
firstname: { key: 'firstname', title: 'Given names', getRowVal: student => student.firstnames, export: false },
Expand Down Expand Up @@ -469,7 +468,9 @@ export const GeneralTab = ({
export: true,
displayColumn: false,
getRowVal: student =>
student.semesterenrollments ? student.semesterenrollments.filter(e => e.enrollmenttype === 1).length : 0,
student.semesterenrollments
? student.semesterenrollments.filter(enrollment => enrollment.enrollmenttype === 1).length
: 0,
},
transferredFrom: {
key: 'transferredFrom',
Expand All @@ -481,7 +482,7 @@ export const GeneralTab = ({
title: 'Admission type',
getRowVal: student => {
const studyright = student.studyrights.find(studyright =>
studyright.studyright_elements.some(e => e.code === programmeCode)
studyright.studyright_elements.some(element => element.code === programmeCode)
)
const admissionType = studyright && studyright.admission_type ? studyright.admission_type : 'Ei valintatapaa'
return admissionType !== 'Koepisteet' ? admissionType : 'Valintakoe'
Expand Down Expand Up @@ -526,7 +527,7 @@ export const GeneralTab = ({
key: 'latestAttainmentDate',
title: 'Latest attainment date',
getRowVal: student => {
const studyPlan = student.studyplans.find(sp => sp.programme_code === programmeCode)
const studyPlan = student.studyplans.find(plan => plan.programme_code === programmeCode)
if (!studyPlan) return ''
const { included_courses: coursesInStudyPlan } = studyPlan

Expand Down Expand Up @@ -571,12 +572,13 @@ export const GeneralTab = ({
getRowVal: student => reformatDate(student.updatedAt, 'YYYY-MM-DD HH:mm:ss'),
},
}
// Columns are shown in order they're declared above. JS guarantees this order of keys
// to stay for non-integer keys

// Columns are shown in order they're declared above. JS
// guarantees this order of keys to stay for non-integer keys
const orderOfColumns = Object.values(columnsAvailable).reduce(
(acc, curr, ind) => ({
(acc, curr, index) => ({
...acc,
[curr.key]: ind,
[curr.key]: index,
}),
{}
)
Expand All @@ -590,7 +592,7 @@ export const GeneralTab = ({
return (
<SortableTable
columns={columns}
data={selectedStudents.map(sn => students[sn])}
data={selectedStudents.map(studentNumber => students[studentNumber])}
featureName="students"
onlyExportColumns={hiddenNameAndEmailForExcel}
style={{ height: '80vh' }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,49 @@
import { findStudyrightElementForClass } from '@/common'

export const createMaps = ({ selectedStudents, students, programmeCode, combinedProgrammeCode, year }) => {
const studentToStudyrightStartMap = selectedStudents.reduce((res, sn) => {
const currentStudyright = students[sn].studyrights.find(studyright =>
const studentToStudyrightStartMap = selectedStudents.reduce((res, studentNumber) => {
const currentStudyright = students[studentNumber].studyrights.find(studyright =>
findStudyrightElementForClass([studyright], programmeCode, year)
)
if (currentStudyright?.studyrightid && currentStudyright.studyrightid.slice(-2) === '-2') {
const bachelorId = currentStudyright.studyrightid.replace(/-2$/, '-1')
const bacherlorStudyright = students[sn].studyrights.find(studyright => studyright.studyrightid === bachelorId)
res[sn] = bacherlorStudyright?.startdate || null
const bacherlorStudyright = students[studentNumber].studyrights.find(
studyright => studyright.studyrightid === bachelorId
)
res[studentNumber] = bacherlorStudyright?.startdate || null
} else {
res[sn] = currentStudyright?.startdate || null
res[studentNumber] = currentStudyright?.startdate || null
}
return res
}, {})

const studentToProgrammeStartMap = selectedStudents.reduce((res, sn) => {
const programmeStart = findStudyrightElementForClass(students[sn].studyrights, programmeCode, year)?.startdate
const studentToProgrammeStartMap = selectedStudents.reduce((res, studentNumber) => {
const programmeStart = findStudyrightElementForClass(
students[studentNumber].studyrights,
programmeCode,
year
)?.startdate
// clean up odd bachelor start dates, (givendate)
const studyrightStart = new Date(studentToStudyrightStartMap[sn])
res[sn] = programmeStart ? new Date(Math.max(new Date(programmeStart), studyrightStart)) : studyrightStart
const studyrightStart = new Date(studentToStudyrightStartMap[studentNumber])
res[studentNumber] = programmeStart
? new Date(Math.max(new Date(programmeStart), studyrightStart))
: studyrightStart
return res
}, {})

const studentToStudyrightEndMap = selectedStudents.reduce((res, sn) => {
const targetStudyright = students[sn].studyrights.find(studyright =>
const studentToStudyrightEndMap = selectedStudents.reduce((res, studentNumber) => {
const targetStudyright = students[studentNumber].studyrights.find(studyright =>
findStudyrightElementForClass([studyright], programmeCode, year)
)
res[sn] = targetStudyright && targetStudyright.graduated === 1 ? targetStudyright.enddate : null
res[studentNumber] = targetStudyright && targetStudyright.graduated === 1 ? targetStudyright.enddate : null
return res
}, {})

const studentToSecondStudyrightEndMap = selectedStudents.reduce((res, sn) => {
const targetStudyright = students[sn].studyrights.find(studyright =>
const studentToSecondStudyrightEndMap = selectedStudents.reduce((res, studentNumber) => {
const targetStudyright = students[studentNumber].studyrights.find(studyright =>
studyright.studyright_elements.some(e => e.code === combinedProgrammeCode)
)
res[sn] = targetStudyright && targetStudyright.graduated === 1 ? targetStudyright.enddate : null
res[studentNumber] = targetStudyright && targetStudyright.graduated === 1 ? targetStudyright.enddate : null
return res
}, {})
return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react'
import { reformatDate, getAllProgrammesOfStudent } from '@/common'

import { getAllProgrammesOfStudent, reformatDate } from '@/common'

const noProgrammeDuringCourse = {
en: 'No programme at time of course',
Expand Down
18 changes: 9 additions & 9 deletions services/frontend/src/components/PopulationStudents/index.jsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import moment from 'moment'
import React, { useState, useEffect, useRef } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import React, { useEffect, useRef, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
import { Tab } from 'semantic-ui-react'

import { useTabChangeAnalytics } from '@/common/hooks'
import { coursePopulationToolTips, populationStatisticsToolTips } from '@/common/InfoToolTips'
import { InfoBox } from '@/components/Info/InfoBox'
import { StudentNameVisibilityToggle } from '@/components/StudentNameVisibilityToggle'
import { ConnectedTagList as TagList } from '@/components/TagList'
import { ConnectedTagPopulation as TagPopulation } from '@/components/TagPopulation'
import { useGetAuthorizedUserQuery } from '@/redux/auth'
import { getTagsByStudytrackAction } from '@/redux/tags'
import { getStudentTagsByStudytrackAction } from '@/redux/tagstudent'
import { InfoBox } from '../Info/InfoBox'
import { StudentNameVisibilityToggle } from '../StudentNameVisibilityToggle'
import { ConnectedTagList as TagList } from '../TagList'
import { ConnectedTagPopulation as TagPopulation } from '../TagPopulation'
import { CheckStudentList } from './CheckStudentList'
import { CoursesTabContainer as CoursesTab } from './StudentTable/CourseTab'
import { GeneralTabContainer as GeneralTab } from './StudentTable/GeneralTab'
import { ProgressTable } from './StudentTable/ProgressTab'
import '@/components/PopulationCourseStats/populationCourseStats.css'
import './populationStudents.css'
import '../PopulationCourseStats/populationCourseStats.css'

const Panes = ({
filteredStudents,
Expand Down Expand Up @@ -102,7 +102,7 @@ const Panes = ({
<TagPopulation
combinedProgramme={combinedProgramme}
mainProgramme={mainProgramme}
selectedStudents={filteredStudents.map(stu => stu.studentNumber)}
selectedStudents={filteredStudents.map(student => student.studentNumber)}
tags={tags}
/>
<TagList
Expand Down Expand Up @@ -201,7 +201,7 @@ const PopulationStudents = ({
<span ref={studentRef} style={{ marginRight: '0.5rem' }}>
<InfoBox content={contentToInclude.infotoolTipContent} />
</span>
{admin ? <CheckStudentList students={filteredStudents.map(stu => stu.studentNumber)} /> : null}
{admin ? <CheckStudentList students={filteredStudents.map(student => student.studentNumber)} /> : null}
<Panes
combinedProgramme={combinedProgramme}
coursecode={coursecode}
Expand Down

0 comments on commit 268fc7c

Please sign in to comment.