From 1392fde30df75c82e56853326fadd1d0dce0fe9d Mon Sep 17 00:00:00 2001
From: Albin Henriksson <albhe428@student.liu.se>
Date: Thu, 20 May 2021 20:01:45 +0200
Subject: [PATCH] Fix timer lockout and remove default slide question

---
 .../components/SlideDisplay.tsx                   |  2 +-
 .../components/answerComponents/AnswerMatch.tsx   |  4 ++--
 .../answerComponents/AnswerMultiple.tsx           |  4 ++--
 .../components/answerComponents/AnswerSingle.tsx  |  4 ++--
 .../components/answerComponents/AnswerText.tsx    |  4 ++--
 client/src/pages/views/components/Timer.tsx       |  5 ++++-
 server/app/apis/slides.py                         |  2 +-
 server/app/database/controller/add.py             | 15 +--------------
 server/app/database/controller/copy.py            |  5 +++--
 server/tests/test_app.py                          | 11 +++++------
 server/tests/test_helpers.py                      |  3 ---
 11 files changed, 23 insertions(+), 36 deletions(-)

diff --git a/client/src/pages/presentationEditor/components/SlideDisplay.tsx b/client/src/pages/presentationEditor/components/SlideDisplay.tsx
index b6505eed..05c87d30 100644
--- a/client/src/pages/presentationEditor/components/SlideDisplay.tsx
+++ b/client/src/pages/presentationEditor/components/SlideDisplay.tsx
@@ -64,7 +64,7 @@ const SlideDisplay = ({ variant, activeViewTypeId, currentSlideId }: SlideDispla
             {slide?.timer && (
               <Card style={{ display: 'flex', alignItems: 'center', padding: 10 }}>
                 <TimerIcon fontSize="large" />
-                <Timer variant={variant} />
+                <Timer variant={variant} currentSlideId={currentSlideId} />
               </Card>
             )}
           </SlideDisplayText>
diff --git a/client/src/pages/presentationEditor/components/answerComponents/AnswerMatch.tsx b/client/src/pages/presentationEditor/components/answerComponents/AnswerMatch.tsx
index 15fabf0e..bedd621f 100644
--- a/client/src/pages/presentationEditor/components/answerComponents/AnswerMatch.tsx
+++ b/client/src/pages/presentationEditor/components/answerComponents/AnswerMatch.tsx
@@ -70,7 +70,7 @@ const AnswerMatch = ({ variant, activeSlide, competitionId }: AnswerMultipleProp
   }, [teamId])
 
   const getButtonStyle = () => {
-    if (!(timer.value === null || (timer.enabled && timer.value))) {
+    if (activeSlide?.timer !== undefined && !timer.enabled) {
       return { fill: '#AAAAAA' } // Buttons are light grey if  timer is not on
     }
     return {}
@@ -79,7 +79,7 @@ const AnswerMatch = ({ variant, activeSlide, competitionId }: AnswerMultipleProp
   const onMove = async (previousIndex: number, resultIndex: number) => {
     // moved outside the list
     if (resultIndex < 0 || resultIndex >= sortedAnswers.length || variant !== 'presentation') return
-    if (!(timer.value === null || (timer.enabled && timer.value))) return
+    if (activeSlide?.timer !== undefined && !timer.enabled) return
     const answersCopy = [...sortedAnswers]
     const [removed] = answersCopy.splice(previousIndex, 1)
     answersCopy.splice(resultIndex, 0, removed)
diff --git a/client/src/pages/presentationEditor/components/answerComponents/AnswerMultiple.tsx b/client/src/pages/presentationEditor/components/answerComponents/AnswerMultiple.tsx
index e648845a..c687faf0 100644
--- a/client/src/pages/presentationEditor/components/answerComponents/AnswerMultiple.tsx
+++ b/client/src/pages/presentationEditor/components/answerComponents/AnswerMultiple.tsx
@@ -48,7 +48,7 @@ const AnswerMultiple = ({ variant, activeSlide, competitionId }: AnswerMultipleP
 
   const updateAnswer = async (alternative: QuestionAlternative, checked: boolean) => {
     // TODO: fix. Make list of alternatives and delete & post instead of put to allow multiple boxes checked.
-    if (!(activeSlide && (timer.value === null || (timer.enabled && timer.value)))) {
+    if (!activeSlide || (activeSlide?.timer !== undefined && !timer.enabled)) {
       return
     }
     const url = `/api/competitions/${competitionId}/teams/${teamId}/answers/question_alternatives/${alternative.id}`
@@ -91,7 +91,7 @@ const AnswerMultiple = ({ variant, activeSlide, competitionId }: AnswerMultipleP
           <div key={alt.id}>
             <ListItem divider>
               <GreenCheckbox
-                disabled={!(timer.value === null || (timer.enabled && timer.value))}
+                disabled={activeSlide?.timer !== undefined && !timer.enabled}
                 checked={decideChecked(alt)}
                 onChange={(event: any) => updateAnswer(alt, event.target.checked)}
               />
diff --git a/client/src/pages/presentationEditor/components/answerComponents/AnswerSingle.tsx b/client/src/pages/presentationEditor/components/answerComponents/AnswerSingle.tsx
index 29389c44..70d59c01 100644
--- a/client/src/pages/presentationEditor/components/answerComponents/AnswerSingle.tsx
+++ b/client/src/pages/presentationEditor/components/answerComponents/AnswerSingle.tsx
@@ -50,7 +50,7 @@ const AnswerSingle = ({ variant, activeSlide, competitionId }: AnswerSingleProps
   }
 
   const updateAnswer = async (alternative: QuestionAlternative) => {
-    if (!(activeSlide && (timer.value === null || (timer.enabled && timer.value)))) {
+    if (!activeSlide || (activeSlide?.timer !== undefined && !timer.enabled)) {
       return
     }
 
@@ -79,7 +79,7 @@ const AnswerSingle = ({ variant, activeSlide, competitionId }: AnswerSingleProps
    */
   const renderRadioButton = (alt: QuestionAlternative) => {
     let disabledStyle
-    if (!(timer.value === null || (timer.enabled && timer.value))) {
+    if (activeSlide?.timer !== undefined && !timer.enabled) {
       disabledStyle = { fill: '#AAAAAA' } // Buttons are light grey if  timer is not on
     }
     if (variant === 'presentation') {
diff --git a/client/src/pages/presentationEditor/components/answerComponents/AnswerText.tsx b/client/src/pages/presentationEditor/components/answerComponents/AnswerText.tsx
index b7f0d687..595462c9 100644
--- a/client/src/pages/presentationEditor/components/answerComponents/AnswerText.tsx
+++ b/client/src/pages/presentationEditor/components/answerComponents/AnswerText.tsx
@@ -39,7 +39,7 @@ const AnswerText = ({ activeSlide, competitionId }: AnswerTextProps) => {
       setTimerHandle(undefined)
     }
     //Only updates answer if the timer is on
-    if (timer.value === null || (timer.enabled && timer.value)) {
+    if (activeSlide?.timer !== undefined && !timer.enabled) {
       //Only updates answer 100ms after last input was made
       setTimerHandle(window.setTimeout(() => updateAnswer(answer), 100))
     }
@@ -79,7 +79,7 @@ const AnswerText = ({ activeSlide, competitionId }: AnswerTextProps) => {
       </ListItem>
       <ListItem style={{ height: '100%' }}>
         <TextField
-          disabled={team === undefined || !(timer.value === null || (timer.enabled && timer.value))}
+          disabled={team === undefined || (activeSlide?.timer !== undefined && !timer.enabled)}
           defaultValue={getDefaultString()}
           style={{ height: '100%' }}
           variant="outlined"
diff --git a/client/src/pages/views/components/Timer.tsx b/client/src/pages/views/components/Timer.tsx
index bb65eca4..5b496325 100644
--- a/client/src/pages/views/components/Timer.tsx
+++ b/client/src/pages/views/components/Timer.tsx
@@ -4,9 +4,10 @@ import { useAppDispatch, useAppSelector } from '../../../hooks'
 
 type TimerProps = {
   variant: 'editor' | 'presentation'
+  currentSlideId?: number
 }
 
-const Timer = ({ variant }: TimerProps) => {
+const Timer = ({ variant, currentSlideId }: TimerProps) => {
   const dispatch = useAppDispatch()
   const timer = useAppSelector((state) => state.presentation.timer)
   const [remainingTimer, setRemainingTimer] = useState<number>(0)
@@ -22,6 +23,8 @@ const Timer = ({ variant }: TimerProps) => {
   const displayTime = `${remainingDisplayMinutes}:${remainingDisplaySeconds}`
   const [timerIntervalId, setTimerIntervalId] = useState<NodeJS.Timeout | null>(null)
   const slideTimer = useAppSelector((state) => {
+    if (currentSlideId && variant === 'presentation')
+      return state.presentation.competition.slides.find((slide) => slide.id === currentSlideId)?.timer
     if (variant === 'presentation')
       return state.presentation.competition.slides.find((slide) => slide.id === state.presentation.activeSlideId)?.timer
     return state.editor.competition.slides.find((slide) => slide.id === state.editor.activeSlideId)?.timer
diff --git a/server/app/apis/slides.py b/server/app/apis/slides.py
index b1052c8d..654ee49f 100644
--- a/server/app/apis/slides.py
+++ b/server/app/apis/slides.py
@@ -38,7 +38,7 @@ class SlidesList(Resource):
     def post(self, competition_id):
         """ Posts a new slide to the specified competition. """
 
-        item_slide = dbc.add.slide_without_question(competition_id)
+        item_slide = dbc.add.slide(competition_id)
         return item_response(schema.dump(item_slide))
 
 
diff --git a/server/app/database/controller/add.py b/server/app/database/controller/add.py
index 9d37c8f8..86b6e4b6 100644
--- a/server/app/database/controller/add.py
+++ b/server/app/database/controller/add.py
@@ -125,20 +125,7 @@ def slide(competition_id):
     # Add slide
     item_slide = db_add(Slide(order, competition_id))
 
-    return item_slide
-
-
-def slide_without_question(competition_id):
-    """ Adds a slide to the provided competition. """
-
-    # Get the last order from given competition
-    order = dbc.utils.count(Slide, {"competition_id": competition_id})
-
-    # Add slide
-    item_slide = db_add(Slide(order, competition_id))
-
-    item_slide = dbc.utils.refresh(item_slide)
-    return item_slide
+    return dbc.utils.refresh(item_slide)
 
 
 def competition(name, year, city_id):
diff --git a/server/app/database/controller/copy.py b/server/app/database/controller/copy.py
index d19f6bd3..f2a06fac 100644
--- a/server/app/database/controller/copy.py
+++ b/server/app/database/controller/copy.py
@@ -4,7 +4,8 @@ This file contains functionality to copy and duplicate data to the database.
 
 from app.database.controller import add, get, search, utils
 from app.database.models import Question
-from app.database.types import IMAGE_COMPONENT_ID, QUESTION_COMPONENT_ID, TEXT_COMPONENT_ID
+from app.database.types import (IMAGE_COMPONENT_ID, QUESTION_COMPONENT_ID,
+                                TEXT_COMPONENT_ID)
 
 
 def _alternative(item_old, question_id):
@@ -90,7 +91,7 @@ def slide_to_competition(item_slide_old, item_competition):
     Does not copy team, question answers.
     """
 
-    item_slide_new = add.slide_without_question(item_competition.id)
+    item_slide_new = add.slide(item_competition.id)
 
     # Copy all fields
     item_slide_new.title = item_slide_old.title
diff --git a/server/tests/test_app.py b/server/tests/test_app.py
index 6439c465..e4e46c68 100644
--- a/server/tests/test_app.py
+++ b/server/tests/test_app.py
@@ -9,7 +9,8 @@ import pytest
 from app.core import sockets
 
 from tests import app, client, db
-from tests.test_helpers import add_default_values, change_order_test, delete, get, post, put
+from tests.test_helpers import (add_default_values, change_order_test, delete,
+                                get, post, put)
 
 
 # @pytest.mark.skip(reason="Takes long time")
@@ -398,14 +399,13 @@ def test_question_api(client):
     slide_order = 1
     response, body = get(client, f"/api/competitions/{CID}/questions", headers=headers)
     assert response.status_code == codes.OK
-    assert body["count"] == 2
+    assert body["count"] == 0
 
     # Get questions from another competition that should have some questions
     CID = 3
-    num_questions = 3
     response, body = get(client, f"/api/competitions/{CID}/questions", headers=headers)
     assert response.status_code == codes.OK
-    assert body["count"] == num_questions
+    assert body["count"] == 0
 
     # Add question
     name = "Nytt namn"
@@ -417,7 +417,6 @@ def test_question_api(client):
         {"name": name, "type_id": type_id},
         headers=headers,
     )
-    num_questions = 4
     assert response.status_code == codes.OK
     assert item_question["name"] == name
     assert item_question["type_id"] == type_id
@@ -425,7 +424,7 @@ def test_question_api(client):
     # Checks number of questions
     response, body = get(client, f"/api/competitions/{CID}/questions", headers=headers)
     assert response.status_code == codes.OK
-    assert body["count"] == num_questions
+    assert body["count"] == 1
     """
     # Delete question
     response, _ = delete(client, f"/api/competitions/{CID}/slides/{slide_order}/questions/{QID}", headers=headers)
diff --git a/server/tests/test_helpers.py b/server/tests/test_helpers.py
index 47fa647d..7bcda31a 100644
--- a/server/tests/test_helpers.py
+++ b/server/tests/test_helpers.py
@@ -41,10 +41,7 @@ def add_default_values():
     # Add competitions
     item_competition = dbc.add.competition("Tom tävling", 2012, item_city.id)
 
-    item_question = dbc.add.question("hej", 5, 1, item_competition.slides[0].id)
-
     item_team1 = dbc.add.team("Hej lag 3", item_competition.id)
-    item_team2 = dbc.add.team("Hej lag 4", item_competition.id)
 
     db.session.add(Code("111111", 1, item_competition.id, item_team1.id))  # Team
     db.session.add(Code("222222", 2, item_competition.id))  # Judge
-- 
GitLab