Skip to content

Commit

Permalink
Refactor and bug fixes (#339)
Browse files Browse the repository at this point in the history
This commit contains a lot of refactoring and bug fixes

    KUI-1176
    fix: remove fade in/out
    refactor context, make it read-only and object instead of array containing an object
    refactor call to ug-rest-api
    return 400 if given courseCode has wrong length



* fix(KUI-1176): remove fades

* feat(KUI-1176): remove reordering of courseOfferings

* ref(KUI-1176): refactor context

* chore(git): add coverage to .gitignore

* ref(KUI-1176): consolidate and make use of semesterUtils

* ref(KUI-1176): s/keyList/employees and s/lang/language

* ref(KUI-1176): restructure webContextUtil

* fix(KUI-1176): page renders even if examiners throw

* ref(KUI-1176): extract calculation of initiallySelectedSemester

* ref(KUI-1176): useApi and useCourseEmployees

* ref(KUI-1176): remove addClientFunctionsToWebContext

* ref(KUI-1176): make webContext readOnly

* ref(KUI-1176): make webContext object instead of array

* ref(KUI-1176): change employee endpoint

* ref(KUI-1176): s/term/semester in semesterutils

* fix(KUI-1176): return 400 if given courseCode has wrong length

* fix(KUI-1176) bug in useSemesterRoundState

* fix(KUI-1176): cleaning

* fix(KUI-1176): remove createServerSideContext

* ref(KUI-1176): rename filteredData

* ref(KUI-1176): remove unnecessary CSS

* ref(KUI-1176): improve naming, remove duplicate code

* ref(KUI-1176): rename roundList to roundsBySemester
  • Loading branch information
belanglos authored May 21, 2024
1 parent 950f05d commit bd20c4c
Show file tree
Hide file tree
Showing 63 changed files with 2,876 additions and 1,745 deletions.
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"root": true,
"extends": ["@kth/eslint-config-kth"],
"extends": ["plugin:react-hooks/recommended", "@kth/eslint-config-kth"],
}
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,7 @@ yarn.lock
notes*

# Files downloaded during unit test
course-information-statistics-*
course-information-statistics-*

# Jest coverage
coverage
1 change: 0 additions & 1 deletion i18n/messages.en.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ module.exports = {
course_language: 'Language of instruction',
course_required_equipment: 'Equipment',
course_level_code: 'Education cycle',
course_establishment: 'Fastställande',
course_decision_to_discontinue: 'Avvecklingsbeslut',
course_transitional_reg: 'Transitional regulations',
course_ethical: 'Ethical approach',
Expand Down
1 change: 0 additions & 1 deletion i18n/messages.se.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ module.exports = {
course_language: 'Undervisningsspråk',
course_required_equipment: 'Utrustning',
course_level_code: 'Utbildningsnivå',
course_establishment: 'Fastställande',
course_decision_to_discontinue: 'Avvecklingsbeslut',
course_transitional_reg: 'Övergångsbestämmelser',
course_ethical: 'Etiskt förhållningssätt',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"test:file:watch": "jest ./server/apiCalls/transformers/offerings-over-several-semesters.test.js --watch",
"test:notify": "jest --watch --notify",
"docker": "npm install --development && npm run build && npm prune --production",
"lint": "eslint public server && prettier-eslint --list-different **/*.js",
"lint": "eslint \"{public,server}/**/*.{js,jsx}\"",
"prepare": "husky",
"start": "bash -c 'cat /KTH_NODEJS; NODE_ENV=production node app.js'",
"start-dev": "bash -c 'NODE_ENV=development concurrently --kill-others -n build,app \"npm run build-dev\" \"nodemon app.js\"'"
Expand Down
24 changes: 0 additions & 24 deletions public/css/kursinfo-web.scss
Original file line number Diff line number Diff line change
Expand Up @@ -134,30 +134,6 @@ sup {
}
}

/************************************************/

/* Animation */
#roundInformationOneCol,
#roundKeyInformation,
#coreContent {
@keyframes fadeOutIn {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}

.fadeOutIn {
animation-name: fadeOutIn;
animation-duration: 800ms;
}
}

///******************** MODAL ****************************///
.modal {
.modal-title {
Expand Down
31 changes: 0 additions & 31 deletions public/js/app/client-context/addClientFunctionsToWebContext.jsx

This file was deleted.

This file was deleted.

17 changes: 3 additions & 14 deletions public/js/app/components/CourseSectionList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,8 @@ import { useMissingInfo } from '../hooks/useMissingInfo'
import CourseSection from './CourseSections'
import SyllabusInformation from './SyllabusInformation'

function CourseSectionList({
courseInfo = {},
partToShow,
syllabusList: syllabus = {},
syllabusName,
syllabusSemesterList,
}) {
const [context] = useWebContext()
function CourseSectionList({ courseInfo = {}, partToShow, syllabus = {}, syllabusName, hasSyllabus }) {
const context = useWebContext()
const { translation } = useLanguage()
const { isMissingInfoLabel, missingInfoLabel } = useMissingInfo()

Expand Down Expand Up @@ -193,12 +187,7 @@ function CourseSectionList({
id={partToShow}
aria-label={`${translation.courseLabels.label_course_information} ${syllabusName}`}
>
<SyllabusInformation
context={context}
syllabus={syllabus}
syllabusSemesterList={syllabusSemesterList}
translation={translation}
/>
<SyllabusInformation context={context} syllabus={syllabus} hasSyllabus={hasSyllabus} translation={translation} />
<CourseSection
sectionHeader={translation.courseLabels.header_content}
headerType="3"
Expand Down
101 changes: 53 additions & 48 deletions public/js/app/components/DropdownRounds.jsx
Original file line number Diff line number Diff line change
@@ -1,75 +1,80 @@
import React from 'react'
import { useWebContext } from '../context/WebContext'
import React, { useEffect } from 'react'
import { useRoundUtils } from '../hooks/useRoundUtils'
import { useLanguage } from '../hooks/useLanguage'

const DropdownRounds = ({ courseRoundList, label = '' }) => {
const [context, setWebContext] = useWebContext()
const { roundDisabled } = context
const [roundSelectedIndex, setRoundSelectIndex] = React.useState(0)
const DROPDOWN_ID = 'roundsDropdown'
const EMPTY_OPTION = -1

const RoundOptions = ({ roundsForSelectedSemester }) => {
const { createRoundLabel } = useRoundUtils()

const dropdownID = 'roundsDropdown'
return roundsForSelectedSemester.map((round, roundIndex) => {
const optionLabel = createRoundLabel(round)

async function handleDropdownSelect(e) {
e.preventDefault()
const uniqueKey = `${optionLabel}${round.round_application_code}${round.round_start_date}`

const eTarget = e.target
const selectedOption = eTarget[eTarget.selectedIndex]
return (
<option key={uniqueKey} value={roundIndex}>
{optionLabel}
</option>
)
})
}

const selectInfo = selectedOption.id.split('_')
const DropdownRounds = ({ roundsForSelectedSemester, semesterRoundState }) => {
const { setSelectedRoundIndex, resetSelectedRoundIndex } = semesterRoundState

const newContext = {
activeRoundIndex: eTarget.selectedIndex === 0 ? 0 : selectInfo[1],
showRoundData: eTarget.selectedIndex !== 0,
roundSelectedIndex: eTarget.selectedIndex,
}
setWebContext({ ...context, ...newContext })
const { translation } = useLanguage()
const label = translation.courseLabels.label_round_select

setRoundSelectIndex(eTarget.selectedIndex)
}
const [selectedOptionIndex, setSelectedOptionIndex] = React.useState(EMPTY_OPTION)

useEffect(() => {
setSelectedOptionIndex(EMPTY_OPTION)
}, [roundsForSelectedSemester])

const handleDropdownSelect = React.useCallback(
({ target }) => {
const { value } = target

const selectedOption = parseInt(value)

const isEmptyOption = selectedOption === EMPTY_OPTION

if (courseRoundList && courseRoundList.length < 2) {
return ''
const newActiveRoundIndex = isEmptyOption ? 0 : selectedOption

if (isEmptyOption) {
resetSelectedRoundIndex()
} else {
setSelectedRoundIndex(newActiveRoundIndex)
}

setSelectedOptionIndex(selectedOption)
},
[setSelectedRoundIndex, resetSelectedRoundIndex, setSelectedOptionIndex]
)

if (!roundsForSelectedSemester || roundsForSelectedSemester.length < 2) {
return null
}

return (
<div className="semester-dropdowns">
<form>
<label className="form-control-label" htmlFor={dropdownID}>
<label className="form-control-label" htmlFor={DROPDOWN_ID}>
{label.label_dropdown}
</label>
<div className="form-group">
<div className="select-wrapper">
<select
className="form-select"
id={dropdownID}
aria-label=""
id={DROPDOWN_ID}
onChange={handleDropdownSelect}
disabled={roundDisabled}
value={selectedOptionIndex}
>
(
<option id={dropdownID + '_-1_0'} defaultValue={roundSelectedIndex === 0} value={label.placeholder}>
{label.placeholder}
</option>
(<option value={EMPTY_OPTION}>{label.placeholder}</option>
)
{courseRoundList.map((round, index) => {
const isChosen = roundSelectedIndex - 1 === index
const optionLabel = createRoundLabel(round)

// Key must be unique, otherwise it will not update course rounds list for some courses, ex.FLH3000
const uniqueKey = `${optionLabel}${round.round_application_code}${round.round_start_date}`

return (
<option
key={uniqueKey}
id={dropdownID + '_' + index + '_0'}
defaultValue={isChosen}
value={optionLabel}
>
{optionLabel}
</option>
)
})}
<RoundOptions roundsForSelectedSemester={roundsForSelectedSemester} />
</select>
</div>
</div>
Expand Down
84 changes: 29 additions & 55 deletions public/js/app/components/DropdownSemesters.jsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,44 @@
import React from 'react'
import { useWebContext } from '../context/WebContext'
import { useLanguage } from '../hooks/useLanguage'

const DROPDOWN_ID = 'semesterDropdown'

const formatLongSemesterName = (semesterItem, translation) =>
`${translation.courseInformation.course_short_semester[semesterItem[1]]}${semesterItem[0]}`
`${translation.courseInformation.course_short_semester[semesterItem.semesterNumber]}${semesterItem.year}`

const DropdownSemesters = ({ semesterList, label = '', translation, useStartSemesterFromQuery }) => {
const [context, setWebContext] = useWebContext()
const DropdownSemesters = ({ semesterList, semesterRoundState }) => {
const { translation } = useLanguage()

const dropdownID = 'semesterDropdown'
const { hasStartPeriodFromQuery, semesterSelectedIndex } = context
const label = translation.courseLabels.label_semester_select

const showSelectPlaceholder = (!hasStartPeriodFromQuery && !useStartSemesterFromQuery) || !useStartSemesterFromQuery
const { selectedSemester, setSelectedSemester } = semesterRoundState

if (semesterList && semesterList.length < 1) {
if (!semesterList || (semesterList && semesterList.length < 1)) {
return ''
}

const selectedSemester = !showSelectPlaceholder ? semesterList[semesterSelectedIndex] : null

const selectedOptionValue = selectedSemester
? formatLongSemesterName(selectedSemester, translation)
: label.placeholder

async function handleSemesterDropdownSelect(e) {
e.preventDefault()
const { activeSemesters } = context
const eventTarget = e.target
const selectedOption = eventTarget[eventTarget.selectedIndex]
function handleSemesterDropdownSelect({ target }) {
const { value } = target

const selectInfo = selectedOption.id.split('_')
const newIndex = Number(selectInfo[1])
const activeSemester = activeSemesters[newIndex] ? activeSemesters[newIndex][2].toString() : ''
const showRoundData =
context.courseData.roundList[activeSemester] && context.courseData.roundList[activeSemester].length === 1

const newContext = {
syllabusInfoFade:
context.activeSyllabusIndex !== context.activeSemestersIndexesWithValidSyllabusesIndexes[newIndex],
activeRoundIndex: 0,
activeSemesterIndex: newIndex >= 0 ? newIndex : context.defaultIndex,
activeSemester: activeSemester || (activeSemesters.length > 0 ? activeSemesters[context.defaultIndex][2] : 0),
activeSyllabusIndex: context.activeSemestersIndexesWithValidSyllabusesIndexes[newIndex] || 0,
roundInfoFade: true,
showRoundData,
roundDisabled: newIndex === -1,
semesterSelectedIndex: eventTarget.selectedIndex,
roundSelectedIndex: 0,
}
setWebContext({ ...context, ...newContext })
setSelectedSemester(value)
}

return (
<div className="semester-dropdowns">
<form>
<label className="form-control-label" htmlFor={dropdownID}>
<label className="form-control-label" htmlFor={DROPDOWN_ID}>
{label.label_dropdown}
</label>
<div className="form-group">
<div className="select-wrapper">
<select
className="form-select"
id={dropdownID}
id={DROPDOWN_ID}
aria-label={label.placeholder}
onChange={handleSemesterDropdownSelect}
defaultValue={selectedOptionValue} // selects value
value={selectedSemester}
>
{showSelectPlaceholder && (
<option id={dropdownID + '_-1_0'} value={label.placeholder}>
{label.placeholder}
</option>
)}
{semesterList.map((semesterItem, index) => {
const longSemesterName = formatLongSemesterName(semesterItem, translation)
return (
<option key={longSemesterName} id={dropdownID + '_' + index + '_0'} value={longSemesterName}>
{longSemesterName}
</option>
)
})}
<SemesterOptions semesterList={semesterList} />
</select>
</div>
</div>
Expand All @@ -86,4 +47,17 @@ const DropdownSemesters = ({ semesterList, label = '', translation, useStartSeme
)
}

const SemesterOptions = ({ semesterList }) => {
const { translation } = useLanguage()

return semesterList.map(semesterItem => {
const longSemesterName = formatLongSemesterName(semesterItem, translation)
return (
<option key={longSemesterName} value={semesterItem.semester}>
{longSemesterName}
</option>
)
})
}

export default DropdownSemesters
Loading

0 comments on commit bd20c4c

Please sign in to comment.