mirror of
https://github.com/UniversityOfHelsinkiCS/oodikone.git
synced 2026-10-12 19:03:39 +03:00
Yearly update teacher leaderboard stats button
This commit is contained in:
@@ -20,6 +20,12 @@ router.get('/top', async (req, res) => {
|
||||
res.json(result)
|
||||
})
|
||||
|
||||
router.post('/top', async (req, res) => {
|
||||
const { startyearcode, endyearcode } = req.body
|
||||
res.status(200).end()
|
||||
await topteachers.findAndSaveTeachers(startyearcode, endyearcode)
|
||||
})
|
||||
|
||||
router.get('/top/categories', async (req, res) => {
|
||||
const result = await topteachers.getCategoriesAndYears()
|
||||
res.json(result)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const { Op } = require('sequelize')
|
||||
const sequelize = require('sequelize')
|
||||
const { Semester } = require('../models/index')
|
||||
const { Op } = sequelize
|
||||
|
||||
const getSemestersAndYears = async before => {
|
||||
const semesters = await Semester.findAll({
|
||||
@@ -24,6 +25,15 @@ const getSemestersAndYears = async before => {
|
||||
return result
|
||||
}
|
||||
|
||||
const getMaxYearcode = async () => {
|
||||
const aa = await Semester.findAll({
|
||||
attributes: [[sequelize.fn('max', sequelize.col('yearcode')), 'maxYearCode']],
|
||||
raw: true
|
||||
})
|
||||
return aa[0].maxYearCode
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getSemestersAndYears
|
||||
getSemestersAndYears,
|
||||
getMaxYearcode
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
const { redisClient } = require('./redis')
|
||||
const { getSemestersAndYears } = require('./semesters')
|
||||
const { getSemestersAndYears, getMaxYearcode } = require('./semesters')
|
||||
const { Teacher, Semester, Credit, Course } = require('../models/index')
|
||||
const { Op } = require('sequelize')
|
||||
|
||||
@@ -126,6 +126,13 @@ const findTopTeachers = async (yearcode) => {
|
||||
}
|
||||
}
|
||||
|
||||
const findAndSaveTeachers = async (startcode = 50, to) => {
|
||||
const endcode = to ? to : await getMaxYearcode()
|
||||
for (let code = startcode; code <= endcode; code++) {
|
||||
await findAndSaveTopTeachers(code)
|
||||
}
|
||||
}
|
||||
|
||||
const findAndSaveTopTeachers = async yearcode => {
|
||||
const { all, openuni } = await findTopTeachers(yearcode)
|
||||
await setTeacherStats(ID.OPENUNI, yearcode, openuni)
|
||||
@@ -138,6 +145,7 @@ module.exports = {
|
||||
setTeacherStats,
|
||||
getCategoriesAndYears,
|
||||
findTopTeachers,
|
||||
findAndSaveTeachers,
|
||||
findAndSaveTopTeachers,
|
||||
ID
|
||||
}
|
||||
@@ -1,31 +1,20 @@
|
||||
import React, { Component } from 'react'
|
||||
import { Segment, Form } from 'semantic-ui-react'
|
||||
import { connect } from 'react-redux'
|
||||
import { func, arrayOf, shape, string, any } from 'prop-types'
|
||||
import { func, arrayOf, shape, string, any, number } from 'prop-types'
|
||||
import { getTopTeachers } from '../../redux/teachersTop'
|
||||
|
||||
class LeaderForm extends Component {
|
||||
state={
|
||||
selectedyear: null,
|
||||
selectedcategory: null
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { year, category } = this.defaultValues()
|
||||
if (year && category) {
|
||||
this.updateAndSubmitForm({
|
||||
this.props.updateAndSubmitForm({
|
||||
selectedyear: year,
|
||||
selectedcategory: category
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
updateAndSubmitForm = (args) => {
|
||||
this.setState(args)
|
||||
const { selectedyear, selectedcategory } = { ...this.state, ...args }
|
||||
this.props.getTopTeachers(selectedyear, selectedcategory)
|
||||
}
|
||||
|
||||
defaultValues = () => {
|
||||
const { yearoptions, categoryoptions } = this.props
|
||||
const [defaultyear = {}] = yearoptions
|
||||
@@ -36,8 +25,6 @@ class LeaderForm extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleChange = (e, { value, name }) => this.updateAndSubmitForm({ [name]: value })
|
||||
|
||||
render() {
|
||||
const { yearoptions, categoryoptions } = this.props
|
||||
return (
|
||||
@@ -51,8 +38,8 @@ class LeaderForm extends Component {
|
||||
options={yearoptions}
|
||||
selection
|
||||
search
|
||||
value={this.state.selectedyear}
|
||||
onChange={this.handleChange}
|
||||
value={this.props.selectedyear}
|
||||
onChange={this.props.handleChange}
|
||||
/>
|
||||
<Form.Dropdown
|
||||
name="selectedcategory"
|
||||
@@ -61,8 +48,8 @@ class LeaderForm extends Component {
|
||||
options={categoryoptions}
|
||||
selection
|
||||
search
|
||||
value={this.state.selectedcategory}
|
||||
onChange={this.handleChange}
|
||||
value={this.props.selectedcategory}
|
||||
onChange={this.props.handleChange}
|
||||
/>
|
||||
</Form.Group>
|
||||
</Form>
|
||||
@@ -74,7 +61,10 @@ class LeaderForm extends Component {
|
||||
LeaderForm.propTypes = {
|
||||
yearoptions: arrayOf(shape({})).isRequired,
|
||||
categoryoptions: arrayOf(shape({ key: any, value: any, text: string })).isRequired,
|
||||
getTopTeachers: func.isRequired
|
||||
updateAndSubmitForm: func.isRequired,
|
||||
handleChange: func.isRequired,
|
||||
selectedcategory: string, // eslint-disable-line
|
||||
selectedyear: number // eslint-disable-line
|
||||
}
|
||||
|
||||
export default connect(null, { getTopTeachers })(LeaderForm)
|
||||
|
||||
@@ -1,34 +1,91 @@
|
||||
import React, { Component } from 'react'
|
||||
import { Segment, Message } from 'semantic-ui-react'
|
||||
import { Segment, Message, Button, Popup } from 'semantic-ui-react'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { connect } from 'react-redux'
|
||||
import { func, arrayOf, bool, shape, any, string } from 'prop-types'
|
||||
import { getTopTeachersCategories } from '../../redux/teachersTopCategories'
|
||||
import { getTopTeachers } from '../../redux/teachersTop'
|
||||
import TeacherStatisticsTable from '../TeacherStatisticsTable'
|
||||
import LeaderForm from './LeaderForm'
|
||||
import { callApi } from '../../apiConnection'
|
||||
|
||||
class TeacherLeaderBoard extends Component {
|
||||
state={}
|
||||
state = {
|
||||
selectedyear: null,
|
||||
selectedcategory: null,
|
||||
recalculating: false,
|
||||
isOpen: false
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.getTopTeachersCategories()
|
||||
}
|
||||
|
||||
handleOpen = () => {
|
||||
this.setState({ isOpen: true, recalculating: true })
|
||||
|
||||
this.timeout = setTimeout(() => {
|
||||
this.setState({ isOpen: false })
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({ isOpen: false })
|
||||
clearTimeout(this.timeout)
|
||||
}
|
||||
|
||||
refresh = () => {
|
||||
const { selectedyear } = this.state
|
||||
callApi('/teachers/top', 'post', { startyearcode: selectedyear, endyearcode: selectedyear + 1 }, null)
|
||||
}
|
||||
|
||||
updateAndSubmitForm = (args) => {
|
||||
this.setState({ recalculating: false, ...args })
|
||||
const { selectedyear, selectedcategory } = { ...this.state, ...args }
|
||||
this.props.getTopTeachers(selectedyear, selectedcategory)
|
||||
}
|
||||
|
||||
handleChange = (e, { value, name }) => this.updateAndSubmitForm({ [name]: value })
|
||||
|
||||
render() {
|
||||
const { statistics, updated, isLoading, yearoptions, categoryoptions } = this.props
|
||||
const { selectedcategory, selectedyear, recalculating } = this.state
|
||||
return (
|
||||
<div>
|
||||
{ isLoading
|
||||
{isLoading
|
||||
? <Segment basic loading={isLoading} />
|
||||
: (
|
||||
<div>
|
||||
<Message
|
||||
header="Teacher leaderboard"
|
||||
content="Teachers who have produced the most credits from all departments."
|
||||
<Message>
|
||||
<Message.Header>Teacher leaderboard</Message.Header>
|
||||
Teachers who have produced the most credits from all departments.
|
||||
</Message>
|
||||
<LeaderForm
|
||||
yearoptions={yearoptions}
|
||||
categoryoptions={categoryoptions}
|
||||
handleChange={this.handleChange}
|
||||
updateAndSubmitForm={this.updateAndSubmitForm}
|
||||
selectedcategory={selectedcategory}
|
||||
selectedyear={selectedyear}
|
||||
/>
|
||||
<LeaderForm yearoptions={yearoptions} categoryoptions={categoryoptions} />
|
||||
<Segment>
|
||||
<Message size="tiny" content={`Last updated: ${updated}`} />
|
||||
<Message>
|
||||
{`Last updated: ${updated}`}
|
||||
</Message>
|
||||
<Popup
|
||||
trigger={
|
||||
<Button
|
||||
disabled={recalculating}
|
||||
content="Recalculate this year"
|
||||
onClick={() => { this.refresh() }}
|
||||
/>}
|
||||
content="Recalculation started. Recalculation might take multiple minutes. Refresh page to see the results"
|
||||
on="click"
|
||||
open={this.state.isOpen}
|
||||
onClose={this.handleClose}
|
||||
onOpen={this.handleOpen}
|
||||
/>
|
||||
|
||||
<TeacherStatisticsTable
|
||||
statistics={statistics}
|
||||
onClickFn={e => this.props.history.push(`/teachers/${e.target.innerText}`)}
|
||||
@@ -48,6 +105,7 @@ TeacherLeaderBoard.propTypes = {
|
||||
yearoptions: arrayOf(shape({})).isRequired,
|
||||
history: shape({}).isRequired,
|
||||
updated: string.isRequired,
|
||||
getTopTeachers: func.isRequired,
|
||||
getTopTeachersCategories: func.isRequired,
|
||||
categoryoptions: arrayOf(shape({ key: any, text: string, value: any })).isRequired
|
||||
}
|
||||
@@ -76,5 +134,6 @@ const mapStateToProps = ({ teachersTop, teachersTopCategories }) => {
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, {
|
||||
getTopTeachersCategories
|
||||
getTopTeachersCategories,
|
||||
getTopTeachers
|
||||
})(withRouter(TeacherLeaderBoard))
|
||||
|
||||
Reference in New Issue
Block a user