Compare commits

...
13 Commits
6 changed files with 68 additions and 53 deletions
+1
View File
@@ -2,6 +2,7 @@
Master:
[![Build Status](https://travis-ci.org/UniversityOfHelsinkiCS/oodikone2-frontend.svg?branch=master)](https://travis-ci.org/UniversityOfHelsinkiCS/oodikone2-frontend)
Trunk:
[![Build Status](https://travis-ci.org/UniversityOfHelsinkiCS/oodikone2-frontend.svg?branch=trunk)](https://travis-ci.org/UniversityOfHelsinkiCS/oodikone2-frontend)
+4
View File
@@ -50,6 +50,10 @@ export const dateFromApiToDisplay = date =>
export const sortDatesWithFormat = (d1, d2, dateFormat) =>
moment(d1, dateFormat) - moment(d2, dateFormat)
export const byDateDesc = (a, b) => new Date(b.date) - new Date(a.date)
export const byName = (a, b) => a.name.localeCompare(b.name)
/* This should be done in backend */
export const removeInvalidCreditsFromStudent = student => ({
...student,
+9 -8
View File
@@ -6,6 +6,7 @@ import { Search, Dropdown, Header, List, Button } from 'semantic-ui-react'
import CourseStatistics from '../CourseStatistics'
import Timeout from '../Timeout'
import { byDateDesc, reformatDate, byName } from '../../common'
import { findCourses } from '../../redux/courses'
import { findCourseInstances, getCourseInstanceStatistics, removeInstance } from '../../redux/courseInstances'
@@ -24,14 +25,14 @@ class Courses extends Component {
state = {
isLoading: false,
searchStr: '',
selectedCourse: { name: 'No course', code: 'No code' }
selectedCourse: { name: 'No course selected', code: '' }
}
resetComponent = () => {
this.setState({
isLoading: false,
searchStr: '',
selectedCourse: { name: 'No course', code: 'No code' }
selectedCourse: { name: 'No course selected', code: '' }
})
}
@@ -81,11 +82,12 @@ class Courses extends Component {
render() {
const { isLoading, searchStr, selectedCourse } = this.state
const { courseInstances, selectedInstances } = this.props
const courseList = this.props.courseList.map(course => ({ ...course, key: `${course.name}-${course.code}` }))
const instanceList = courseInstances ? courseInstances.map(instance => ({
const courseList = this.props.courseList.sort(byName).map(course => ({ ...course, key: `${course.name}-${course.code}` }))
const instanceList = courseInstances ? courseInstances.sort(byDateDesc).map(instance => ({
key: instance.id,
text: `${instance.date} (${instance.students} students)`,
text: `${reformatDate(instance.date, 'DD.MM.YYYY')} (${instance.students} students)`,
value: instance.id
})) : []
@@ -100,7 +102,6 @@ class Courses extends Component {
{instance.date}
</List.Item>))
// const t = this.props.translate;
return (
<div className={styles.container}>
<Search
@@ -115,7 +116,7 @@ class Courses extends Component {
/>
<Header as="h2">
{selectedCourse.name}
{selectedCourse.name} {selectedCourse.code ? `(${selectedCourse.code})` : ''}
</Header>
<Dropdown
@@ -135,7 +136,7 @@ class Courses extends Component {
<CourseStatistics
key={i.id}
courseName={i.course.name}
instanceDate={i.date}
instanceDate={reformatDate(i.date, 'DD.MM.YYYY')}
stats={i.statistics}
/>
))}
@@ -18,7 +18,7 @@ class CreditAccumulationGraph extends Component {
state = {
combinedStudentData: undefined,
studentCreditLines: [],
intervalObject: undefined,
timeout: undefined,
loading: true
}
@@ -26,61 +26,63 @@ class CreditAccumulationGraph extends Component {
const { students } = this.props
const combinedStudentData = this.createCombinedStudentData(students)
this.getMoreCreditLines()
this.setState({ combinedStudentData, loading: true })
const timeout = setTimeout(() => this.getMoreCreditLines(students), 1000)
this.setState({ combinedStudentData, timeout, loading: true })
}
componentWillReceiveProps(nextProps) {
if (nextProps.students) {
const nextStudents = nextProps.students.map(student => student.studentNumber)
const oldStudents = this.props.students.map(student => student.studentNumber)
const changed = nextStudents.some(student => !oldStudents.includes(student)) ||
oldStudents.some(student => !nextStudents.includes(student))
if (changed) {
const { students } = nextProps
const timeout = setTimeout(() => this.getMoreCreditLines(students), 1000)
const combinedStudentData = this.createCombinedStudentData(students)
this.setState({ combinedStudentData, timeout, loading: true })
}
}
}
componentWillUnmount() {
if (this.state.intervalObject) {
clearInterval(this.state.intervalObject.interval)
if (this.state.timeout) {
clearInterval(this.state.timeout)
}
}
getMoreCreditLines = () => {
const { students } = this.props
const { intervalObject } = this.state
const MAX_SPLICES = Math.min(Math.ceil(students.length / 30), 1) // Made up
if (!intervalObject) {
const interval = setInterval(() => this.getMoreCreditLines(), 1000)
this.setState({ intervalObject: { interval, tick: 0 } })
return
}
const newInterval = { ...intervalObject, tick: 1 + intervalObject.tick }
let loading = true
if (newInterval.tick === MAX_SPLICES) {
clearInterval(intervalObject.interval)
loading = false
}
getMoreCreditLines = (students) => {
const studentCreditLines = this.state.studentCreditLines.concat(this.createStudentCreditLines(
students.slice(
this.state.studentCreditLines.length,
Math.ceil(students.length / (MAX_SPLICES - intervalObject.tick))
),
students,
this.isSingleStudentGraph(students)
))
this.setState({ intervalObject: newInterval, studentCreditLines, loading })
this.setState({ studentCreditLines, loading: false })
}
getXAxisMonth = (date, startDate) =>
Math.max(moment(date, API_DATE_FORMAT).diff(moment(startDate, API_DATE_FORMAT), 'days') / 30, 0)
getReferenceLineForStudent = (student) => {
const { courses, started } = student
const lastDate = moment(_.maxBy(courses, course => moment(course.date)).date)
const lastMonth = Math.ceil(this.getXAxisMonth(lastDate, started))
const lastCredits = lastMonth * (55 / 12)
try {
const { courses, started } = student
const lastDate = moment(_.maxBy(courses, course => moment(course.date)).date)
const lastMonth = Math.ceil(this.getXAxisMonth(lastDate, started))
const lastCredits = lastMonth * (55 / 12)
return [{
month: 0,
referenceCredits: 0,
date: reformatDate(started, DISPLAY_DATE_FORMAT)
},
{
month: lastMonth,
referenceCredits: lastCredits,
date: reformatDate(lastDate, DISPLAY_DATE_FORMAT)
}]
return [{
month: 0,
referenceCredits: 0,
date: reformatDate(started, DISPLAY_DATE_FORMAT)
},
{
month: lastMonth,
referenceCredits: lastCredits,
date: reformatDate(lastDate, DISPLAY_DATE_FORMAT)
}]
} catch (e) {
return null
}
}
@@ -183,8 +185,12 @@ class CreditAccumulationGraph extends Component {
const referenceData = this.getReferenceLineForStudent(students[0])
combinedStudentData = combinedStudentData.concat(referenceData)
}
return combinedStudentData.sort((c1, c2) =>
sortDatesWithFormat(c1.date, c2.date, DISPLAY_DATE_FORMAT))
try {
return combinedStudentData.sort((c1, c2) =>
sortDatesWithFormat(c1.date, c2.date, DISPLAY_DATE_FORMAT))
} catch (e) {
return null
}
}
render() {
+5 -2
View File
@@ -7,7 +7,7 @@ import { isEmpty } from 'lodash'
import StudentInfoCard from '../StudentInfoCard'
import CreditAccumulationGraph from '../CreditAccumulationGraph'
import SearchResultTable from '../SearchResultTable'
import { removeInvalidCreditsFromStudent } from '../../common'
import { removeInvalidCreditsFromStudent, byDateDesc, reformatDate } from '../../common'
import sharedStyles from '../../styles/shared'
@@ -45,7 +45,10 @@ class StudentDetails extends Component {
return (
<SearchResultTable
headers={courseHeaders}
rows={courseRows}
rows={courseRows.sort(byDateDesc).map(c => ({
...c,
date: reformatDate(c.date, 'DD.MM.YYYY')
}))}
noResultText={translate('common.noResults')}
/>
)
+1 -1
View File
@@ -55,7 +55,7 @@
},
"studentStatistics": {
"header" : ["Student statistics"],
"searchPlaceholder": ["Search with a student number or name"],
"searchPlaceholder": ["Search with a student number or name (surname firstname)"],
"chartTitle" : ["Credit Accumulation"]
},
"tags": {