Skip to content
Snippets Groups Projects
Commit dd6c9422 authored by Emil's avatar Emil
Browse files

fix: text question bug, feat: show answers in judge view

parent 554db4fe
No related branches found
No related tags found
1 merge request!153fix: text question bug, feat: show answers in judge view
Pipeline #45902 passed with warnings
......@@ -59,10 +59,10 @@ const AnswerText = ({ activeSlide, competitionId }: AnswerTextProps) => {
if (!team || !activeSlide) {
return
}
const activeAltId = activeSlide.questions[0].alternatives[0].id
const activeAltId = activeSlide.questions[0]?.alternatives[0]?.id
return (
team.question_alternative_answers.find((questionAnswer) => questionAnswer.question_alternative_id === activeAltId)
?.answer || 'Svar...'
?.answer || ''
)
}
......
......@@ -39,7 +39,6 @@ const SlideType = ({ activeSlide, competitionId }: SlideTypeProps) => {
const components = useAppSelector(
(state) => state.editor.competition.slides.find((slide) => slide.id === state.editor.activeSlideId)?.components
)
const questionComponentId = components?.find((qCompId) => qCompId.type_id === 3)?.id
const openSlideTypeDialog = (type_id: number) => {
setSelectedSlideType(type_id)
......@@ -82,6 +81,21 @@ const SlideType = ({ activeSlide, competitionId }: SlideTypeProps) => {
removeQuestionComponent().then(() => createQuestionComponent(data.id))
})
.catch(console.log)
if (selectedSlideType === 1) {
// Add an alternative to text questions to allow giving answers.
await axios
.post(
`/api/competitions/${competitionId}/slides/${activeSlide.id}/questions/${activeSlide.questions[0].id}/alternatives`,
{
text: '',
value: 1,
}
)
.then(({ data }) => {
dispatch(getEditorCompetition(competitionId))
})
.catch(console.log)
}
}
} else if (!activeSlide.questions[0] && selectedSlideType !== 0) {
// Change slide type from information to a question type
......@@ -96,6 +110,21 @@ const SlideType = ({ activeSlide, competitionId }: SlideTypeProps) => {
createQuestionComponent(data.id)
})
.catch(console.log)
if (selectedSlideType === 1) {
// Add an alternative to text questions to allow giving answers.
await axios
.post(
`/api/competitions/${competitionId}/slides/${activeSlide.id}/questions/${activeSlide.questions[0].id}/alternatives`,
{
text: '',
value: 1,
}
)
.then(({ data }) => {
dispatch(getEditorCompetition(competitionId))
})
.catch(console.log)
}
}
}
}
......@@ -157,7 +186,7 @@ const SlideType = ({ activeSlide, competitionId }: SlideTypeProps) => {
<DialogContent>
<DialogContentText>
Om du ändrar sidtypen kommer eventuella frågeinställningar gå förlorade. Det inkluderar: frågans namn,
poäng och svarsalternativ.{' '}
poäng, svarsalternativ och svar från lagen.{' '}
</DialogContentText>
</DialogContent>
<DialogActions>
......
......@@ -2,7 +2,7 @@ import { Divider, List, ListItemText, Snackbar, Typography } from '@material-ui/
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
import { Alert } from '@material-ui/lab'
import React, { useEffect, useState } from 'react'
import { getPresentationCompetition } from '../../actions/presentation'
import { getPresentationCompetition, setPresentationTimer } from '../../actions/presentation'
import { useAppDispatch, useAppSelector } from '../../hooks'
import { RichSlide } from '../../interfaces/ApiRichModels'
import { socketConnect } from '../../sockets'
......@@ -53,7 +53,6 @@ const JudgeViewPage: React.FC = () => {
const [currentSlide, setCurrentSlide] = useState<RichSlide | undefined>(undefined)
const currentQuestion = currentSlide?.questions[0]
const operatorActiveSlideId = useAppSelector((state) => state.presentation.activeSlideId)
const timer = useAppSelector((state) => state.presentation.timer)
const operatorActiveSlideOrder = useAppSelector(
(state) => state.presentation.competition.slides.find((slide) => slide.id === operatorActiveSlideId)?.order
)
......@@ -74,14 +73,35 @@ const JudgeViewPage: React.FC = () => {
dispatch(getPresentationCompetition(competitionId.toString()))
}
}, [operatorActiveSlideId])
// useEffect(() => {
// // Every second tic of the timer, load new answers
// // TODO: use a set interval that updates every second ( look in Timer.tsx in clien/src/pages/views/components )
// // Then clear interval when timer - Date.now() is negative
// if (timer !== null && timer - (Date.now() % 2) === 0 && competitionId) {
// dispatch(getPresentationCompetition(competitionId.toString()))
// }
// }, [timer])
const timer = useAppSelector((state) => state.presentation.timer)
const [timerIntervalId, setTimerIntervalId] = useState<NodeJS.Timeout | null>(null)
useEffect(() => {
if (!timer.enabled) {
if (timerIntervalId !== null && competitionId) {
clearInterval(timerIntervalId)
dispatch(getPresentationCompetition(competitionId.toString()))
}
return
}
setTimerIntervalId(
setInterval(() => {
if (timer.value === null) return
if (timer.value - Date.now() < 0) {
if (competitionId) {
dispatch(getPresentationCompetition(competitionId.toString()))
}
dispatch(setPresentationTimer({ ...timer, enabled: false }))
return
}
if (competitionId) {
dispatch(getPresentationCompetition(competitionId.toString()))
}
}, 1000)
)
}, [timer.enabled])
return (
<div style={{ height: '100%' }}>
<JudgeAppBar position="fixed">
......
import { Box, Typography } from '@material-ui/core'
import { Box, Divider, Typography } from '@material-ui/core'
import axios from 'axios'
import React from 'react'
import { getPresentationCompetition } from '../../../actions/presentation'
import { useAppDispatch, useAppSelector } from '../../../hooks'
import { RichSlide } from '../../../interfaces/ApiRichModels'
import { AnswerContainer, ScoreDisplayContainer, ScoreDisplayHeader, ScoreInput } from './styled'
import {
AnswerContainer,
Answers,
AnswersDisplay,
ScoreDisplayContainer,
ScoreDisplayHeader,
ScoreInput,
} from './styled'
type ScoreDisplayProps = {
teamIndex: number
......@@ -13,7 +20,6 @@ type ScoreDisplayProps = {
const JudgeScoreDisplay = ({ teamIndex, activeSlide }: ScoreDisplayProps) => {
const dispatch = useAppDispatch()
const questionTypes = useAppSelector((state) => state.types.questionTypes)
const currentTeam = useAppSelector((state) => state.presentation.competition.teams[teamIndex])
const currentCompetititonId = useAppSelector((state) => state.presentation.competition.id)
......@@ -22,7 +28,6 @@ const JudgeScoreDisplay = ({ teamIndex, activeSlide }: ScoreDisplayProps) => {
const questionMaxScore = activeQuestion?.total_score
const scores = currentTeam.question_scores.map((questionAnswer) => questionAnswer.score)
const textQuestionType = questionTypes.find((questionType) => questionType.name === 'Text')?.id || 0
const handleEditScore = async (newScore: number, questionId: number) => {
await axios
.put(`/api/competitions/${currentCompetititonId}/teams/${currentTeam.id}/answers/question_scores/${questionId}`, {
......@@ -31,33 +36,38 @@ const JudgeScoreDisplay = ({ teamIndex, activeSlide }: ScoreDisplayProps) => {
.then(() => dispatch(getPresentationCompetition(currentCompetititonId.toString())))
}
const getAlternativeAnswers = () => {
const getAnswers = () => {
const result: string[] = []
if (!activeQuestion) {
return result
}
for (const alt of activeQuestion.alternatives) {
const value = currentTeam.question_alternative_answers.find((x) => x.question_alternative_id === alt.id)
if (!value) {
const ans = currentTeam.question_alternative_answers.find((x) => x.question_alternative_id === alt.id)
if (!ans) {
continue
}
if (activeQuestion.type_id === 1) {
result.push(alt.text)
} else if (+value.answer > 0) {
// Text question
result.push(ans.answer)
} else if (+ans.answer > 0) {
result.push(alt.text)
}
/*
switch(activeQuestion.question_type.name){
case "Text":
result.push(alt.text)
break;
default:
}*/
}
return result
}
const getAlternatives = () => {
const result: string[] = []
if (!activeQuestion) {
return result
}
for (const alt of activeQuestion.alternatives) {
if (activeQuestion.type_id !== 1 && +alt.value > 0) {
// Not text question and correct answer
result.push(alt.text)
}
}
return result
//const asdasd = currentTeam.question_alternative_answers.filter((x)=>x.question_alternative_id === activeQuestion.alternatives[0].io)
}
return (
......@@ -81,15 +91,37 @@ const JudgeScoreDisplay = ({ teamIndex, activeSlide }: ScoreDisplayProps) => {
</ScoreDisplayHeader>
<Typography variant="h6">Alla poäng: [ {scores.map((score) => `${score} `)}]</Typography>
<Typography variant="h6">Total poäng: {scores.reduce((a, b) => a + b, 0)}</Typography>
{activeQuestion && (
<AnswerContainer>
{getAlternativeAnswers().map((v, k) => (
<Typography variant="body1" key={k}>
<span>&#8226;</span> {v}
</Typography>
))}
</AnswerContainer>
)}
<AnswersDisplay>
<Answers>
<Divider />
<Typography variant="body1">Lagets svar:</Typography>
{activeQuestion && (
<AnswerContainer>
{getAnswers().map((v, k) => (
<Typography variant="body1" key={k}>
<span>&#8226;</span> {v}
</Typography>
))}
</AnswerContainer>
)}
</Answers>
<Answers>
<Divider />
<Typography variant="body1">Korrekta svar:</Typography>
{activeQuestion && (
<AnswerContainer>
{getAlternatives().map((v, k) => (
<Typography variant="body1" key={k}>
<span>&#8226;</span> {v}
</Typography>
))}
</AnswerContainer>
)}
</Answers>
</AnswersDisplay>
{!activeQuestion && <Typography variant="body1">Inget svar</Typography>}
</ScoreDisplayContainer>
)
......
......@@ -48,3 +48,16 @@ export const ScoringInstructionsInner = styled.div`
align-items: center;
flex-direction: column;
`
export const AnswersDisplay = styled.div`
display: flex;
flex-direction: row;
`
export const Answers = styled.div`
margin-left: 15px;
margin-right: 15px;
display: flex;
align-items: center;
flex-direction: column;
`
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment