From 4cff23cbf788fa7c72bfca9865e9b31b5162d05d Mon Sep 17 00:00:00 2001
From: Albin Henriksson <albhe428@student.liu.se>
Date: Sun, 9 May 2021 20:19:03 +0000
Subject: [PATCH] Resolve "Minor fixes"

---
 client/src/actions/competitionLogin.ts        |   8 +-
 client/src/actions/competitions.ts            |   5 +
 client/src/actions/presentation.test.ts       |  36 ++---
 client/src/actions/presentation.ts            |  25 +---
 client/src/actions/types.ts                   |   6 +-
 client/src/pages/admin/AdminPage.tsx          |  27 +++-
 .../admin/competitions/AddCompetition.tsx     |   5 +-
 .../admin/competitions/CompetitionManager.tsx |   9 +-
 client/src/pages/admin/regions/AddRegion.tsx  |   5 +-
 client/src/pages/admin/regions/Regions.tsx    |  18 +--
 client/src/pages/admin/users/AddUser.tsx      |  10 +-
 client/src/pages/login/styled.tsx             |   1 +
 .../PresentationEditorPage.tsx                |   4 +-
 .../components/CompetitionSettings.tsx        |  18 +--
 .../components/ImageComponentDisplay.tsx      |   2 +
 .../components/QuestionComponentDisplay.tsx   |   7 +-
 .../components/RndComponent.tsx               |   2 +-
 .../components/SlideDisplay.tsx               |  37 +++--
 .../answerComponents/AnswerText.tsx           |   7 +-
 .../slideSettingsComponents/Timer.tsx         |   4 +-
 client/src/pages/views/AudienceViewPage.tsx   |  12 +-
 client/src/pages/views/JudgeViewPage.tsx      |  59 +++++---
 client/src/pages/views/OperatorViewPage.tsx   |  28 +++-
 client/src/pages/views/TeamViewPage.tsx       |  15 +-
 .../views/components/JudgeScoreDisplay.tsx    |   9 +-
 .../components/JudgeScoringInstructions.tsx   |   1 +
 .../components/PresentationComponent.tsx      |   5 +-
 client/src/pages/views/components/Timer.tsx   |  28 ++--
 client/src/reducers/editorReducer.ts          |   5 +
 .../src/reducers/presentationReducer.test.ts  | 138 +-----------------
 client/src/reducers/presentationReducer.ts    |  39 +----
 client/src/sockets.ts                         |  18 ++-
 client/src/utils/SecureRoute.tsx              |   2 +-
 .../checkAuthenticationCompetition.test.ts    |  14 +-
 .../utils/checkAuthenticationCompetition.ts   |  12 +-
 35 files changed, 263 insertions(+), 358 deletions(-)

diff --git a/client/src/actions/competitionLogin.ts b/client/src/actions/competitionLogin.ts
index d9f28333..cfc222b3 100644
--- a/client/src/actions/competitionLogin.ts
+++ b/client/src/actions/competitionLogin.ts
@@ -18,7 +18,7 @@ export const loginCompetition = (code: string, history: History, redirect: boole
     .post('/api/auth/login/code', { code })
     .then((res) => {
       const token = `Bearer ${res.data.access_token}`
-      localStorage.setItem('competitionToken', token) //setting token to local storage
+      localStorage.setItem(`${res.data.view}Token`, token) //setting token to local storage
       axios.defaults.headers.common['Authorization'] = token //setting authorize token to header in axios
       dispatch({ type: Types.CLEAR_COMPETITION_LOGIN_ERRORS }) // no error
       dispatch({
@@ -41,8 +41,10 @@ export const loginCompetition = (code: string, history: History, redirect: boole
 }
 
 // Log out from competition and remove jwt token from local storage and axios
-export const logoutCompetition = () => async (dispatch: AppDispatch) => {
-  localStorage.removeItem('competitionToken')
+export const logoutCompetition = (role: 'Judge' | 'Operator' | 'Team' | 'Audience') => async (
+  dispatch: AppDispatch
+) => {
+  localStorage.removeItem(`${role}Token`)
   await axios.post('/api/auth/logout').then(() => {
     delete axios.defaults.headers.common['Authorization']
     dispatch({
diff --git a/client/src/actions/competitions.ts b/client/src/actions/competitions.ts
index bae48138..64fd11e1 100644
--- a/client/src/actions/competitions.ts
+++ b/client/src/actions/competitions.ts
@@ -44,3 +44,8 @@ export const getCompetitions = () => async (dispatch: AppDispatch, getState: ()
 export const setFilterParams = (params: CompetitionFilterParams) => (dispatch: AppDispatch) => {
   dispatch({ type: Types.SET_COMPETITIONS_FILTER_PARAMS, payload: params })
 }
+
+// DIspatch action to set loading
+export const setEditorLoading = (loading: boolean) => (dispatch: AppDispatch) => {
+  dispatch({ type: Types.SET_EDITOR_LOADING, payload: loading })
+}
diff --git a/client/src/actions/presentation.test.ts b/client/src/actions/presentation.test.ts
index 095a3529..9fbc2a0d 100644
--- a/client/src/actions/presentation.test.ts
+++ b/client/src/actions/presentation.test.ts
@@ -3,12 +3,7 @@ import expect from 'expect' // You can use any testing library
 import configureMockStore from 'redux-mock-store'
 import thunk from 'redux-thunk'
 import { Slide } from '../interfaces/ApiModels'
-import {
-  getPresentationCompetition,
-  setCurrentSlide,
-  setCurrentSlideNext,
-  setCurrentSlidePrevious,
-} from './presentation'
+import { getPresentationCompetition, setCurrentSlideByOrder } from './presentation'
 import Types from './types'
 
 const middlewares = [thunk]
@@ -26,23 +21,16 @@ it('dispatches no actions when failing to get competitions', async () => {
 })
 
 it('dispatches correct actions when setting slide', () => {
-  const testSlide: Slide = { competition_id: 0, id: 5, order: 5, timer: 20, title: '', background_image: undefined }
-  const expectedActions = [{ type: Types.SET_PRESENTATION_SLIDE, payload: testSlide }]
-  const store = mockStore({})
-  setCurrentSlide(testSlide)(store.dispatch)
-  expect(store.getActions()).toEqual(expectedActions)
-})
-
-it('dispatches correct actions when setting previous slide', () => {
-  const expectedActions = [{ type: Types.SET_PRESENTATION_SLIDE_PREVIOUS }]
-  const store = mockStore({})
-  setCurrentSlidePrevious()(store.dispatch)
-  expect(store.getActions()).toEqual(expectedActions)
-})
-
-it('dispatches correct actions when setting next slide', () => {
-  const expectedActions = [{ type: Types.SET_PRESENTATION_SLIDE_NEXT }]
-  const store = mockStore({})
-  setCurrentSlideNext()(store.dispatch)
+  const testSlide: Slide = {
+    competition_id: 0,
+    id: 123123,
+    order: 43523,
+    timer: 20,
+    title: '',
+    background_image: undefined,
+  }
+  const expectedActions = [{ type: Types.SET_PRESENTATION_SLIDE_ID, payload: testSlide.id }]
+  const store = mockStore({ presentation: { competition: { id: 2, slides: [testSlide] } } })
+  setCurrentSlideByOrder(testSlide.order)(store.dispatch, store.getState as any)
   expect(store.getActions()).toEqual(expectedActions)
 })
diff --git a/client/src/actions/presentation.ts b/client/src/actions/presentation.ts
index 07536b21..0c3f2466 100644
--- a/client/src/actions/presentation.ts
+++ b/client/src/actions/presentation.ts
@@ -3,7 +3,6 @@ This file handles actions for the presentation redux state
 */
 
 import axios from 'axios'
-import { Slide } from '../interfaces/ApiModels'
 import { Timer } from '../interfaces/Timer'
 import store, { AppDispatch, RootState } from './../store'
 import Types from './types'
@@ -17,8 +16,8 @@ export const getPresentationCompetition = (id: string) => async (dispatch: AppDi
         type: Types.SET_PRESENTATION_COMPETITION,
         payload: res.data,
       })
-      if (getState().presentation?.slide.id === -1 && res.data?.slides[0]) {
-        setCurrentSlideByOrder(0)(dispatch)
+      if (getState().presentation?.activeSlideId === -1 && res.data?.slides[0]) {
+        setCurrentSlideByOrder(0)(dispatch, getState)
       }
     })
     .catch((err) => {
@@ -26,24 +25,10 @@ export const getPresentationCompetition = (id: string) => async (dispatch: AppDi
     })
 }
 
-/** Set presentation slide using input slide id */
-export const setCurrentSlide = (slide: Slide) => (dispatch: AppDispatch) => {
-  dispatch({ type: Types.SET_PRESENTATION_SLIDE, payload: slide })
-}
-
-/** Set presentation slide to previous slide in list */
-export const setCurrentSlidePrevious = () => (dispatch: AppDispatch) => {
-  dispatch({ type: Types.SET_PRESENTATION_SLIDE_PREVIOUS })
-}
-
-/** Set presentation slide to next slide in list */
-export const setCurrentSlideNext = () => (dispatch: AppDispatch) => {
-  dispatch({ type: Types.SET_PRESENTATION_SLIDE_NEXT })
-}
-
 /** Set presentation slide using input order */
-export const setCurrentSlideByOrder = (order: number) => (dispatch: AppDispatch) => {
-  dispatch({ type: Types.SET_PRESENTATION_SLIDE_BY_ORDER, payload: order })
+export const setCurrentSlideByOrder = (order: number) => (dispatch: AppDispatch, getState: () => RootState) => {
+  const slideId = getState().presentation.competition.slides.find((slide) => slide.order === order)?.id
+  dispatch({ type: Types.SET_PRESENTATION_SLIDE_ID, payload: slideId })
 }
 
 /** Set code of presentation */
diff --git a/client/src/actions/types.ts b/client/src/actions/types.ts
index c73179c1..eca08ccd 100644
--- a/client/src/actions/types.ts
+++ b/client/src/actions/types.ts
@@ -37,13 +37,11 @@ export default {
   SET_EDITOR_COMPETITION: 'SET_EDITOR_COMPETITION',
   SET_EDITOR_SLIDE_ID: 'SET_EDITOR_SLIDE_ID',
   SET_EDITOR_VIEW_ID: 'SET_EDITOR_VIEW_ID',
+  SET_EDITOR_LOADING: 'SET_EDITOR_LOADING',
 
   // Presentation action types
   SET_PRESENTATION_COMPETITION: 'SET_PRESENTATION_COMPETITION',
-  SET_PRESENTATION_SLIDE: 'SET_PRESENTATION_SLIDE',
-  SET_PRESENTATION_SLIDE_PREVIOUS: 'SET_PRESENTATION_SLIDE_PREVIOUS',
-  SET_PRESENTATION_SLIDE_NEXT: 'SET_PRESENTATION_SLIDE_NEXT',
-  SET_PRESENTATION_SLIDE_BY_ORDER: 'SET_PRESENTATION_SLIDE_BY_ORDER',
+  SET_PRESENTATION_SLIDE_ID: 'SET_PRESENTATION_SLIDE_ID',
   SET_PRESENTATION_CODE: 'SET_PRESENTATION_CODE',
   SET_PRESENTATION_TIMER: 'SET_PRESENTATION_TIMER',
 
diff --git a/client/src/pages/admin/AdminPage.tsx b/client/src/pages/admin/AdminPage.tsx
index 3a375210..8d193557 100644
--- a/client/src/pages/admin/AdminPage.tsx
+++ b/client/src/pages/admin/AdminPage.tsx
@@ -19,6 +19,7 @@ import SettingsOverscanIcon from '@material-ui/icons/SettingsOverscan'
 import React, { useEffect } from 'react'
 import { Link, Route, Switch, useRouteMatch } from 'react-router-dom'
 import { getCities } from '../../actions/cities'
+import { setEditorLoading } from '../../actions/competitions'
 import { getRoles } from '../../actions/roles'
 import { getStatistics } from '../../actions/statistics'
 import { getTypes } from '../../actions/typesAction'
@@ -73,6 +74,7 @@ const AdminView: React.FC = () => {
     dispatch(getRoles())
     dispatch(getTypes())
     dispatch(getStatistics())
+    dispatch(setEditorLoading(true))
   }, [])
 
   const menuAdminItems = [
@@ -87,6 +89,21 @@ const AdminView: React.FC = () => {
     { text: 'Tävlingshanterare', icon: SettingsOverscanIcon },
   ]
 
+  const getPathName = (tabName: string) => {
+    switch (tabName) {
+      case 'Startsida':
+        return 'dashboard'
+      case 'Regioner':
+        return 'regions'
+      case 'Användare':
+        return 'users'
+      case 'Tävlingshanterare':
+        return 'competition-manager'
+      default:
+        return ''
+    }
+  }
+
   const renderItems = () => {
     const menuItems = isAdmin ? menuAdminItems : menuEditorItems
     return menuItems.map((value, index) => (
@@ -95,7 +112,7 @@ const AdminView: React.FC = () => {
         button
         component={Link}
         key={value.text}
-        to={`${url}/${value.text.toLowerCase()}`}
+        to={`${url}/${getPathName(value.text)}`}
         selected={index === openIndex}
         onClick={() => setOpenIndex(index)}
       >
@@ -147,16 +164,16 @@ const AdminView: React.FC = () => {
       <main className={classes.content}>
         <div className={classes.toolbar} />
         <Switch>
-          <Route exact path={[path, `${path}/startsida`]}>
+          <Route exact path={[path, `${path}/dashboard`]}>
             <Dashboard />
           </Route>
-          <Route path={`${path}/regioner`}>
+          <Route path={`${path}/regions`}>
             <RegionManager />
           </Route>
-          <Route path={`${path}/användare`}>
+          <Route path={`${path}/users`}>
             <UserManager />
           </Route>
-          <Route path={`${path}/tävlingshanterare`}>
+          <Route path={`${path}/competition-manager`}>
             <CompetitionManager />
           </Route>
         </Switch>
diff --git a/client/src/pages/admin/competitions/AddCompetition.tsx b/client/src/pages/admin/competitions/AddCompetition.tsx
index e404b112..165d17d8 100644
--- a/client/src/pages/admin/competitions/AddCompetition.tsx
+++ b/client/src/pages/admin/competitions/AddCompetition.tsx
@@ -1,4 +1,5 @@
 import { Button, FormControl, InputLabel, MenuItem, Popover, TextField } from '@material-ui/core'
+import PostAddIcon from '@material-ui/icons/PostAdd'
 import { Alert, AlertTitle } from '@material-ui/lab'
 import axios from 'axios'
 import { Formik, FormikHelpers } from 'formik'
@@ -89,10 +90,10 @@ const AddCompetition: React.FC = (props: any) => {
     <div>
       <AddButton
         data-testid="addCompetition"
-        style={{ backgroundColor: '#4caf50', color: '#fcfcfc' }}
-        color="default"
+        color="secondary"
         variant="contained"
         onClick={handleClick}
+        endIcon={<PostAddIcon />}
       >
         Ny Tävling
       </AddButton>
diff --git a/client/src/pages/admin/competitions/CompetitionManager.tsx b/client/src/pages/admin/competitions/CompetitionManager.tsx
index cf5332a0..05451028 100644
--- a/client/src/pages/admin/competitions/CompetitionManager.tsx
+++ b/client/src/pages/admin/competitions/CompetitionManager.tsx
@@ -38,6 +38,7 @@ import { getCompetitions, setFilterParams } from '../../../actions/competitions'
 import { useAppDispatch, useAppSelector } from '../../../hooks'
 import { Team } from '../../../interfaces/ApiModels'
 import { CompetitionFilterParams } from '../../../interfaces/FilterParams'
+import { Center } from '../../presentationEditor/components/styled'
 import { FilterContainer, RemoveMenuItem, TopBar, YearFilterTextField } from '../styledComp'
 import AddCompetition from './AddCompetition'
 
@@ -384,9 +385,11 @@ const CompetitionManager: React.FC = (props: any) => {
         fullWidth={false}
         fullScreen={false}
       >
-        <DialogTitle id="max-width-dialog-title" className={classes.paper}>
-          Koder för {competitionName}
-        </DialogTitle>
+        <Center>
+          <DialogTitle id="max-width-dialog-title" className={classes.paper} style={{ width: '100%' }}>
+            Koder för {competitionName}
+          </DialogTitle>
+        </Center>
         <DialogContent>
           {/* <DialogContentText>Här visas tävlingskoderna till den valda tävlingen.</DialogContentText> */}
           {codes.map((code) => (
diff --git a/client/src/pages/admin/regions/AddRegion.tsx b/client/src/pages/admin/regions/AddRegion.tsx
index 10cb22bc..14efed4e 100644
--- a/client/src/pages/admin/regions/AddRegion.tsx
+++ b/client/src/pages/admin/regions/AddRegion.tsx
@@ -90,13 +90,12 @@ const AddRegion: React.FC = (props: any) => {
               />
               <AddButton
                 data-testid="regionSubmitButton"
-                style={{ backgroundColor: '#4caf50', color: '#fcfcfc' }}
                 className={classes.button}
-                color="default"
+                color="secondary"
                 variant="contained"
                 type="submit"
               >
-                <AddIcon></AddIcon>
+                <AddIcon />
               </AddButton>
             </Grid>
           </FormControl>
diff --git a/client/src/pages/admin/regions/Regions.tsx b/client/src/pages/admin/regions/Regions.tsx
index 5e2531bb..57f4c101 100644
--- a/client/src/pages/admin/regions/Regions.tsx
+++ b/client/src/pages/admin/regions/Regions.tsx
@@ -64,26 +64,10 @@ const RegionManager: React.FC = (props: any) => {
     setActiveId(id)
   }
 
-  const handleAddCity = async () => {
-    await axios
-      .post(`/api/misc/cities`, { name: newCity })
-      .then(() => {
-        setAnchorEl(null)
-        dispatch(getCities())
-      })
-      .catch(({ response }) => {
-        console.warn(response.data)
-      })
-  }
-
-  const handleChange = (event: any) => {
-    setNewCity(event.target.value)
-  }
-
   return (
     <div>
       <TopBar>
-        <AddRegion></AddRegion>
+        <AddRegion />
       </TopBar>
       <TableContainer component={Paper}>
         <Table className={classes.table} aria-label="simple table">
diff --git a/client/src/pages/admin/users/AddUser.tsx b/client/src/pages/admin/users/AddUser.tsx
index 63549edc..2634751d 100644
--- a/client/src/pages/admin/users/AddUser.tsx
+++ b/client/src/pages/admin/users/AddUser.tsx
@@ -24,10 +24,7 @@ const userSchema: Yup.SchemaOf<formType> = Yup.object({
     .shape({
       name: Yup.string(),
       email: Yup.string().email().required('Email krävs'),
-      password: Yup.string()
-        .required('Lösenord krävs.')
-        .min(6, 'Lösenord måste vara minst 6 tecken.')
-        .matches(/[a-zA-Z]/, 'Lösenord får enbart innehålla a-z, A-Z.'),
+      password: Yup.string().required('Lösenord krävs.').min(6, 'Lösenord måste vara minst 6 tecken.'),
       role: Yup.string().required('Roll krävs').notOneOf([noCitySelected], 'Välj en roll'),
       city: Yup.string().required('Stad krävs').notOneOf([noRoleSelected], 'Välj en stad'),
     })
@@ -88,11 +85,10 @@ const AddUser: React.FC = (props: any) => {
     <div>
       <AddButton
         data-testid="addUserButton"
-        style={{ backgroundColor: '#4caf50', color: '#fcfcfc' }}
-        color="default"
+        color="secondary"
         variant="contained"
         onClick={handleClick}
-        endIcon={<PersonAddIcon></PersonAddIcon>}
+        endIcon={<PersonAddIcon />}
       >
         Ny Användare
       </AddButton>
diff --git a/client/src/pages/login/styled.tsx b/client/src/pages/login/styled.tsx
index c071747e..73c75d54 100644
--- a/client/src/pages/login/styled.tsx
+++ b/client/src/pages/login/styled.tsx
@@ -2,6 +2,7 @@ import { Paper } from '@material-ui/core'
 import styled from 'styled-components'
 
 export const LoginPageContainer = styled.div`
+  padding-top: 5%;
   display: flex;
   justify-content: center;
 `
diff --git a/client/src/pages/presentationEditor/PresentationEditorPage.tsx b/client/src/pages/presentationEditor/PresentationEditorPage.tsx
index d84944b4..d3286065 100644
--- a/client/src/pages/presentationEditor/PresentationEditorPage.tsx
+++ b/client/src/pages/presentationEditor/PresentationEditorPage.tsx
@@ -68,6 +68,7 @@ const PresentationEditorPage: React.FC = () => {
 
   const setActiveSlideId = (id: number) => {
     dispatch(setEditorSlideId(id))
+    dispatch(getEditorCompetition(competitionId))
   }
 
   const createNewSlide = async () => {
@@ -114,6 +115,7 @@ const PresentationEditorPage: React.FC = () => {
     if (clickedViewTypeId) {
       dispatch(setEditorViewId(clickedViewTypeId))
     }
+    dispatch(getEditorCompetition(competitionId))
   }
 
   const onDragEnd = async (result: DropResult) => {
@@ -138,7 +140,7 @@ const PresentationEditorPage: React.FC = () => {
       <CssBaseline />
       <AppBarEditor $leftDrawerWidth={leftDrawerWidth} $rightDrawerWidth={rightDrawerWidth} position="fixed">
         <ToolBarContainer>
-          <Button component={Link} to="/admin/tävlingshanterare" style={{ padding: 0 }}>
+          <Button component={Link} to="/admin/competition-manager" style={{ padding: 0 }}>
             <HomeIcon src="/t8.png" />
           </Button>
           <CompetitionName variant="h5" noWrap>
diff --git a/client/src/pages/presentationEditor/components/CompetitionSettings.tsx b/client/src/pages/presentationEditor/components/CompetitionSettings.tsx
index 9482b660..fd63a4b3 100644
--- a/client/src/pages/presentationEditor/components/CompetitionSettings.tsx
+++ b/client/src/pages/presentationEditor/components/CompetitionSettings.tsx
@@ -1,23 +1,13 @@
-import {
-  Divider,
-  FormControl,
-  InputLabel,
-  ListItem,
-  ListItemText,
-  MenuItem,
-  Select,
-  TextField,
-  Typography,
-} from '@material-ui/core'
-import { Center, ImportedImage, SettingsList, PanelContainer, FirstItem, AddButton } from './styled'
+import { Divider, FormControl, InputLabel, ListItem, MenuItem, Select, TextField, Typography } from '@material-ui/core'
 import axios from 'axios'
-import React, { useState } from 'react'
+import React from 'react'
 import { useParams } from 'react-router-dom'
 import { getEditorCompetition } from '../../../actions/editor'
 import { useAppDispatch, useAppSelector } from '../../../hooks'
 import { City } from '../../../interfaces/ApiModels'
-import Teams from './Teams'
 import BackgroundImageSelect from './BackgroundImageSelect'
+import { FirstItem, PanelContainer, SettingsList } from './styled'
+import Teams from './Teams'
 
 interface CompetitionParams {
   competitionId: string
diff --git a/client/src/pages/presentationEditor/components/ImageComponentDisplay.tsx b/client/src/pages/presentationEditor/components/ImageComponentDisplay.tsx
index e783bdb2..273748f3 100644
--- a/client/src/pages/presentationEditor/components/ImageComponentDisplay.tsx
+++ b/client/src/pages/presentationEditor/components/ImageComponentDisplay.tsx
@@ -13,6 +13,8 @@ const ImageComponentDisplay = ({ component, width, height }: ImageComponentProps
       src={`http://localhost:5000/static/images/${component.media?.filename}`}
       height={height}
       width={width}
+      // Make sure the border looks good all around the image
+      style={{ paddingRight: 2, paddingBottom: 2 }}
       draggable={false}
     />
   )
diff --git a/client/src/pages/presentationEditor/components/QuestionComponentDisplay.tsx b/client/src/pages/presentationEditor/components/QuestionComponentDisplay.tsx
index dd8e2fa8..b43766eb 100644
--- a/client/src/pages/presentationEditor/components/QuestionComponentDisplay.tsx
+++ b/client/src/pages/presentationEditor/components/QuestionComponentDisplay.tsx
@@ -8,13 +8,16 @@ import { Center } from './styled'
 
 type QuestionComponentProps = {
   variant: 'editor' | 'presentation'
+  currentSlideId?: number
 }
 
-const QuestionComponentDisplay = ({ variant }: QuestionComponentProps) => {
+const QuestionComponentDisplay = ({ variant, currentSlideId }: QuestionComponentProps) => {
   const activeSlide = useAppSelector((state) => {
+    if (variant === 'presentation' && currentSlideId)
+      return state.presentation.competition.slides.find((slide) => slide.id === currentSlideId)
     if (variant === 'editor')
       return state.editor.competition.slides.find((slide) => slide.id === state.editor.activeSlideId)
-    return state.presentation.competition.slides.find((slide) => slide.id === state.presentation.slide?.id)
+    return state.presentation.competition.slides.find((slide) => slide.id === state.presentation.activeSlideId)
   })
 
   const timer = activeSlide?.timer
diff --git a/client/src/pages/presentationEditor/components/RndComponent.tsx b/client/src/pages/presentationEditor/components/RndComponent.tsx
index 4c092800..3b40ad74 100644
--- a/client/src/pages/presentationEditor/components/RndComponent.tsx
+++ b/client/src/pages/presentationEditor/components/RndComponent.tsx
@@ -172,7 +172,7 @@ const RndComponent = ({ component, width, height, scale }: RndComponentProps) =>
       }}
     >
       {hover && (
-        <Card elevation={6} style={{ position: 'absolute' }}>
+        <Card elevation={6} style={{ position: 'absolute', zIndex: 10 }}>
           <Tooltip title="Centrera horisontellt">
             <IconButton onClick={handleCenterHorizontal}>X</IconButton>
           </Tooltip>
diff --git a/client/src/pages/presentationEditor/components/SlideDisplay.tsx b/client/src/pages/presentationEditor/components/SlideDisplay.tsx
index e6b60f29..9fd6ed70 100644
--- a/client/src/pages/presentationEditor/components/SlideDisplay.tsx
+++ b/client/src/pages/presentationEditor/components/SlideDisplay.tsx
@@ -1,33 +1,34 @@
+import { Typography } from '@material-ui/core'
 import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'
 import { getTypes } from '../../../actions/typesAction'
 import { useAppDispatch, useAppSelector } from '../../../hooks'
 import PresentationComponent from '../../views/components/PresentationComponent'
 import RndComponent from './RndComponent'
-import { SlideEditorContainer, SlideEditorContainerRatio, SlideEditorPaper } from './styled'
+import { Center, SlideEditorContainer, SlideEditorContainerRatio, SlideEditorPaper } from './styled'
 
 type SlideDisplayProps = {
   //Prop to distinguish between editor and active competition
   variant: 'editor' | 'presentation'
   activeViewTypeId: number
+  //Can be used to force what slide it it's displaying (currently used in judge view)
+  currentSlideId?: number
 }
 
-const SlideDisplay = ({ variant, activeViewTypeId }: SlideDisplayProps) => {
-  const components = useAppSelector((state) => {
+const SlideDisplay = ({ variant, activeViewTypeId, currentSlideId }: SlideDisplayProps) => {
+  const slide = useAppSelector((state) => {
+    if (currentSlideId && variant === 'presentation')
+      return state.presentation.competition.slides.find((slide) => slide.id === currentSlideId)
     if (variant === 'editor')
-      return state.editor.competition.slides.find((slide) => slide.id === state.editor.activeSlideId)?.components
-    return state.presentation.competition.slides.find((slide) => slide.id === state.presentation.slide?.id)?.components
+      return state.editor.competition.slides.find((slide) => slide.id === state.editor.activeSlideId)
+    return state.presentation.competition.slides.find((slide) => slide.id === state.presentation.activeSlideId)
   })
+  const components = slide?.components
   const competitionBackgroundImage = useAppSelector((state) => {
     if (variant === 'editor') return state.editor.competition.background_image
     return state.presentation.competition.background_image
   })
 
-  const slideBackgroundImage = useAppSelector((state) => {
-    if (variant === 'editor')
-      return state.editor.competition.slides.find((slide) => slide.id === state.editor.activeSlideId)?.background_image
-    return state.presentation.competition.slides.find((slide) => slide.id === state.presentation.slide.id)
-      ?.background_image
-  })
+  const slideBackgroundImage = slide?.background_image
   const dispatch = useAppDispatch()
   const editorPaperRef = useRef<HTMLDivElement>(null)
   const [width, setWidth] = useState(0)
@@ -77,8 +78,20 @@ const SlideDisplay = ({ variant, activeViewTypeId }: SlideDisplayProps) => {
                       scale={scale}
                     />
                   )
-                return <PresentationComponent key={component.id} component={component} scale={scale} />
+                return (
+                  <PresentationComponent
+                    key={component.id}
+                    component={component}
+                    scale={scale}
+                    currentSlideId={currentSlideId}
+                  />
+                )
               })}
+          {!slide && (
+            <Center>
+              <Typography variant="body2"> Ingen sida är vald, välj en i vänstermenyn eller skapa en ny.</Typography>
+            </Center>
+          )}
         </SlideEditorPaper>
       </SlideEditorContainerRatio>
     </SlideEditorContainer>
diff --git a/client/src/pages/presentationEditor/components/answerComponents/AnswerText.tsx b/client/src/pages/presentationEditor/components/answerComponents/AnswerText.tsx
index e54b0dd2..465bffcb 100644
--- a/client/src/pages/presentationEditor/components/answerComponents/AnswerText.tsx
+++ b/client/src/pages/presentationEditor/components/answerComponents/AnswerText.tsx
@@ -1,7 +1,7 @@
 import { ListItem, ListItemText, TextField } from '@material-ui/core'
 import axios from 'axios'
 import React from 'react'
-import { getEditorCompetition } from '../../../../actions/editor'
+import { getPresentationCompetition } from '../../../../actions/presentation'
 import { useAppDispatch, useAppSelector } from '../../../../hooks'
 import { RichSlide } from '../../../../interfaces/ApiRichModels'
 import { Center } from '../styled'
@@ -29,13 +29,14 @@ const AnswerText = ({ activeSlide, competitionId }: AnswerTextProps) => {
 
   const updateAnswer = async (answer: string) => {
     if (activeSlide && team) {
+      console.log(team.question_answers)
       if (team?.question_answers.find((answer) => answer.question_id === activeSlide.questions[0].id)) {
         await axios
           .put(`/api/competitions/${competitionId}/teams/${teamId}/answers/${answerId}`, {
             answer,
           })
           .then(() => {
-            dispatch(getEditorCompetition(competitionId))
+            dispatch(getPresentationCompetition(competitionId))
           })
           .catch(console.log)
       } else {
@@ -46,7 +47,7 @@ const AnswerText = ({ activeSlide, competitionId }: AnswerTextProps) => {
             question_id: activeSlide.questions[0].id,
           })
           .then(() => {
-            dispatch(getEditorCompetition(competitionId))
+            dispatch(getPresentationCompetition(competitionId))
           })
           .catch(console.log)
       }
diff --git a/client/src/pages/presentationEditor/components/slideSettingsComponents/Timer.tsx b/client/src/pages/presentationEditor/components/slideSettingsComponents/Timer.tsx
index 91825662..a633efec 100644
--- a/client/src/pages/presentationEditor/components/slideSettingsComponents/Timer.tsx
+++ b/client/src/pages/presentationEditor/components/slideSettingsComponents/Timer.tsx
@@ -17,7 +17,7 @@ const Timer = ({ activeSlide, competitionId }: TimerProps) => {
     setTimer(+event.target.value)
     if (activeSlide) {
       await axios
-        .put(`/api/competitions/${competitionId}/slides/${activeSlide.id}`, { timer: event.target.value })
+        .put(`/api/competitions/${competitionId}/slides/${activeSlide.id}`, { timer: event.target.value || null })
         .then(() => {
           dispatch(getEditorCompetition(competitionId))
         })
@@ -40,7 +40,7 @@ const Timer = ({ activeSlide, competitionId }: TimerProps) => {
           label="Timer"
           type="number"
           onChange={updateTimer}
-          value={timer}
+          value={timer || ''}
         />
       </Center>
     </ListItem>
diff --git a/client/src/pages/views/AudienceViewPage.tsx b/client/src/pages/views/AudienceViewPage.tsx
index 28280c90..af1f18b3 100644
--- a/client/src/pages/views/AudienceViewPage.tsx
+++ b/client/src/pages/views/AudienceViewPage.tsx
@@ -1,5 +1,6 @@
-import { Typography } from '@material-ui/core'
-import React, { useEffect } from 'react'
+import { Snackbar, Typography } from '@material-ui/core'
+import { Alert } from '@material-ui/lab'
+import React, { useEffect, useState } from 'react'
 import { useAppSelector } from '../../hooks'
 import { socketConnect, socketJoinPresentation } from '../../sockets'
 import SlideDisplay from '../presentationEditor/components/SlideDisplay'
@@ -9,9 +10,11 @@ const AudienceViewPage: React.FC = () => {
   const code = useAppSelector((state) => state.presentation.code)
   const viewTypes = useAppSelector((state) => state.types.viewTypes)
   const activeViewTypeId = viewTypes.find((viewType) => viewType.name === 'Audience')?.id
+  const [successMessageOpen, setSuccessMessageOpen] = useState(true)
+  const competitionName = useAppSelector((state) => state.presentation.competition.name)
   useEffect(() => {
     if (code && code !== '') {
-      socketConnect()
+      socketConnect('Audience')
       socketJoinPresentation()
     }
   }, [])
@@ -21,6 +24,9 @@ const AudienceViewPage: React.FC = () => {
         <PresentationContainer>
           <SlideDisplay variant="presentation" activeViewTypeId={activeViewTypeId} />
         </PresentationContainer>
+        <Snackbar open={successMessageOpen} autoHideDuration={4000} onClose={() => setSuccessMessageOpen(false)}>
+          <Alert severity="success">{`Du har gått med i tävlingen "${competitionName}" som åskådare`}</Alert>
+        </Snackbar>
       </PresentationBackground>
     )
   }
diff --git a/client/src/pages/views/JudgeViewPage.tsx b/client/src/pages/views/JudgeViewPage.tsx
index 81f70edb..a28348a7 100644
--- a/client/src/pages/views/JudgeViewPage.tsx
+++ b/client/src/pages/views/JudgeViewPage.tsx
@@ -1,11 +1,11 @@
-import { Divider, List, ListItemText, Typography } from '@material-ui/core'
+import { Divider, List, ListItemText, Snackbar, Typography } from '@material-ui/core'
 import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
+import { Alert } from '@material-ui/lab'
 import React, { useEffect, useState } from 'react'
-import { useHistory, useParams } from 'react-router-dom'
-import { getPresentationCompetition, setCurrentSlide } from '../../actions/presentation'
+import { getPresentationCompetition } from '../../actions/presentation'
 import { useAppDispatch, useAppSelector } from '../../hooks'
-import { ViewParams } from '../../interfaces/ViewParams'
-import { socketConnect } from '../../sockets'
+import { RichSlide } from '../../interfaces/ApiRichModels'
+import { socketConnect, socketJoinPresentation } from '../../sockets'
 import { renderSlideIcon } from '../../utils/renderSlideIcon'
 import SlideDisplay from '../presentationEditor/components/SlideDisplay'
 import { SlideListItem } from '../presentationEditor/styled'
@@ -42,29 +42,46 @@ const useStyles = makeStyles((theme: Theme) =>
 
 const JudgeViewPage: React.FC = () => {
   const classes = useStyles()
-  const history = useHistory()
   const dispatch = useAppDispatch()
-  const [activeSlideIndex, setActiveSlideIndex] = useState<number>(0)
   const viewTypes = useAppSelector((state) => state.types.viewTypes)
+  const code = useAppSelector((state) => state.presentation.code)
   const activeViewTypeId = viewTypes.find((viewType) => viewType.name === 'Team')?.id
   const teams = useAppSelector((state) => state.presentation.competition.teams)
   const slides = useAppSelector((state) => state.presentation.competition.slides)
-  const currentQuestion = slides[activeSlideIndex]?.questions[0]
-  const { competitionId }: ViewParams = useParams()
+  const [successMessageOpen, setSuccessMessageOpen] = useState(true)
+  const competitionName = useAppSelector((state) => state.presentation.competition.name)
+  const [currentSlide, setCurrentSlide] = useState<RichSlide | undefined>(undefined)
+  const currentQuestion = currentSlide?.questions[0]
+  const operatorActiveSlideId = useAppSelector((state) => state.presentation.activeSlideId)
+  const operatorActiveSlideOrder = useAppSelector(
+    (state) => state.presentation.competition.slides.find((slide) => slide.id === operatorActiveSlideId)?.order
+  )
+  const competitionId = useAppSelector((state) => state.competitionLogin.data?.competition_id)
   const handleSelectSlide = (index: number) => {
-    setActiveSlideIndex(index)
-    dispatch(setCurrentSlide(slides[index]))
+    setCurrentSlide(slides[index])
   }
   useEffect(() => {
-    socketConnect()
-    dispatch(getPresentationCompetition(competitionId))
+    if (code && code !== '') {
+      socketConnect('Judge')
+      socketJoinPresentation()
+    }
   }, [])
-
+  useEffect(() => {
+    if (!currentSlide) setCurrentSlide(slides?.[0])
+  }, [slides])
+  useEffect(() => {
+    if (competitionId) {
+      dispatch(getPresentationCompetition(competitionId.toString()))
+    }
+  }, [operatorActiveSlideId])
   return (
     <div style={{ height: '100%' }}>
       <JudgeAppBar position="fixed">
         <JudgeToolbar>
           <JudgeQuestionsLabel variant="h5">Frågor</JudgeQuestionsLabel>
+          {operatorActiveSlideOrder !== undefined && (
+            <Typography variant="h5">Operatör är på sida: {operatorActiveSlideOrder + 1}</Typography>
+          )}
           <JudgeAnswersLabel variant="h5">Svar</JudgeAnswersLabel>
         </JudgeToolbar>
       </JudgeAppBar>
@@ -80,11 +97,12 @@ const JudgeViewPage: React.FC = () => {
         <List>
           {slides.map((slide, index) => (
             <SlideListItem
-              selected={index === activeSlideIndex}
+              selected={slide.order === currentSlide?.order}
               onClick={() => handleSelectSlide(index)}
               divider
               button
               key={slide.id}
+              style={{ border: 2, borderStyle: slide.id === operatorActiveSlideId ? 'dashed' : 'none' }}
             >
               {renderSlideIcon(slide)}
               <ListItemText primary={`Sida ${slide.order + 1}`} />
@@ -111,20 +129,25 @@ const JudgeViewPage: React.FC = () => {
           {teams &&
             teams.map((answer, index) => (
               <div key={answer.name}>
-                <JudgeScoreDisplay teamIndex={index} />
+                {currentSlide && <JudgeScoreDisplay teamIndex={index} activeSlide={currentSlide} />}
                 <Divider />
               </div>
             ))}
         </List>
         <ScoreFooterPadding />
-        <JudgeScoringInstructions question={currentQuestion} />
+        {currentQuestion && <JudgeScoringInstructions question={currentQuestion} />}
       </RightDrawer>
       <div className={classes.toolbar} />
       <Content leftDrawerWidth={leftDrawerWidth} rightDrawerWidth={rightDrawerWidth}>
         <InnerContent>
-          {activeViewTypeId && <SlideDisplay variant="presentation" activeViewTypeId={activeViewTypeId} />}
+          {activeViewTypeId && currentSlide && (
+            <SlideDisplay variant="presentation" currentSlideId={currentSlide.id} activeViewTypeId={activeViewTypeId} />
+          )}
         </InnerContent>
       </Content>
+      <Snackbar open={successMessageOpen} autoHideDuration={4000} onClose={() => setSuccessMessageOpen(false)}>
+        <Alert severity="success">{`Du har gått med i tävlingen "${competitionName}" som domare`}</Alert>
+      </Snackbar>
     </div>
   )
 }
diff --git a/client/src/pages/views/OperatorViewPage.tsx b/client/src/pages/views/OperatorViewPage.tsx
index 8bd782f7..5bb96fcb 100644
--- a/client/src/pages/views/OperatorViewPage.tsx
+++ b/client/src/pages/views/OperatorViewPage.tsx
@@ -12,6 +12,7 @@ import {
   ListItemText,
   makeStyles,
   Popover,
+  Snackbar,
   Theme,
   Tooltip,
   Typography,
@@ -24,8 +25,9 @@ import FileCopyIcon from '@material-ui/icons/FileCopy'
 import LinkIcon from '@material-ui/icons/Link'
 import SupervisorAccountIcon from '@material-ui/icons/SupervisorAccount'
 import TimerIcon from '@material-ui/icons/Timer'
+import { Alert } from '@material-ui/lab'
 import axios from 'axios'
-import React, { useEffect } from 'react'
+import React, { useEffect, useState } from 'react'
 import { useHistory } from 'react-router-dom'
 import { useAppSelector } from '../../hooks'
 import { RichTeam } from '../../interfaces/ApiRichModels'
@@ -39,6 +41,7 @@ import {
   socketStartTimer,
 } from '../../sockets'
 import SlideDisplay from '../presentationEditor/components/SlideDisplay'
+import { Center } from '../presentationEditor/components/styled'
 import Timer from './components/Timer'
 import {
   OperatorButton,
@@ -111,9 +114,13 @@ const OperatorViewPage: React.FC = () => {
   const history = useHistory()
   const viewTypes = useAppSelector((state) => state.types.viewTypes)
   const activeViewTypeId = viewTypes.find((viewType) => viewType.name === 'Audience')?.id
-
+  const [successMessageOpen, setSuccessMessageOpen] = useState(true)
+  const activeSlideOrder = useAppSelector(
+    (state) =>
+      state.presentation.competition.slides.find((slide) => slide.id === state.presentation.activeSlideId)?.order
+  )
   useEffect(() => {
-    socketConnect()
+    socketConnect('Operator')
     socketSetSlide
     handleOpenCodes()
     setTimeout(startCompetition, 1000) // Wait for socket to connect
@@ -155,7 +162,7 @@ const OperatorViewPage: React.FC = () => {
   const endCompetition = () => {
     setOpen(false)
     socketEndPresentation()
-    history.push('/admin/tävlingshanterare')
+    history.push('/admin/competition-manager')
     window.location.reload(false) // TODO: fix this, we "need" to refresh site to be able to run the competition correctly again
   }
 
@@ -225,9 +232,11 @@ const OperatorViewPage: React.FC = () => {
         fullWidth={false}
         fullScreen={false}
       >
-        <DialogTitle id="max-width-dialog-title" className={classes.paper}>
-          Koder för {competitionName}
-        </DialogTitle>
+        <Center>
+          <DialogTitle id="max-width-dialog-title" className={classes.paper} style={{ width: '100%' }}>
+            Koder för {competitionName}
+          </DialogTitle>
+        </Center>
         <DialogContent>
           {/* <DialogContentText>Här visas tävlingskoderna till den valda tävlingen.</DialogContentText> */}
           {codes &&
@@ -297,7 +306,7 @@ const OperatorViewPage: React.FC = () => {
         <Typography variant="h3">{presentation.competition.name}</Typography>
         <SlideCounter>
           <Typography variant="h3">
-            {presentation.slide.order + 1} / {presentation.competition.slides.length}
+            {activeSlideOrder !== undefined && activeSlideOrder + 1} / {presentation.competition.slides.length}
           </Typography>
         </SlideCounter>
       </OperatorHeader>
@@ -364,6 +373,9 @@ const OperatorViewPage: React.FC = () => {
             ))}
         </List>
       </Popover>
+      <Snackbar open={successMessageOpen} autoHideDuration={4000} onClose={() => setSuccessMessageOpen(false)}>
+        <Alert severity="success">{`Du har gått med i tävlingen "${competitionName}" som operatör`}</Alert>
+      </Snackbar>
     </OperatorContainer>
   )
 }
diff --git a/client/src/pages/views/TeamViewPage.tsx b/client/src/pages/views/TeamViewPage.tsx
index c2d2ff83..fd51c884 100644
--- a/client/src/pages/views/TeamViewPage.tsx
+++ b/client/src/pages/views/TeamViewPage.tsx
@@ -1,4 +1,6 @@
-import React, { useEffect } from 'react'
+import { Snackbar } from '@material-ui/core'
+import { Alert } from '@material-ui/lab'
+import React, { useEffect, useState } from 'react'
 import { useAppSelector } from '../../hooks'
 import { socketConnect, socketJoinPresentation } from '../../sockets'
 import SlideDisplay from '../presentationEditor/components/SlideDisplay'
@@ -8,9 +10,15 @@ const TeamViewPage: React.FC = () => {
   const code = useAppSelector((state) => state.presentation.code)
   const viewTypes = useAppSelector((state) => state.types.viewTypes)
   const activeViewTypeId = viewTypes.find((viewType) => viewType.name === 'Team')?.id
+  const [successMessageOpen, setSuccessMessageOpen] = useState(true)
+  const competitionName = useAppSelector((state) => state.presentation.competition.name)
+  const teamName = useAppSelector(
+    (state) =>
+      state.presentation.competition.teams.find((team) => team.id === state.competitionLogin.data?.team_id)?.name
+  )
   useEffect(() => {
     if (code && code !== '') {
-      socketConnect()
+      socketConnect('Team')
       socketJoinPresentation()
     }
   }, [])
@@ -19,6 +27,9 @@ const TeamViewPage: React.FC = () => {
       <PresentationContainer>
         {activeViewTypeId && <SlideDisplay variant="presentation" activeViewTypeId={activeViewTypeId} />}
       </PresentationContainer>
+      <Snackbar open={successMessageOpen} autoHideDuration={4000} onClose={() => setSuccessMessageOpen(false)}>
+        <Alert severity="success">{`Du har gått med i tävlingen "${competitionName}" som lag ${teamName}`}</Alert>
+      </Snackbar>
     </PresentationBackground>
   )
 }
diff --git a/client/src/pages/views/components/JudgeScoreDisplay.tsx b/client/src/pages/views/components/JudgeScoreDisplay.tsx
index 2745e129..0b5e5845 100644
--- a/client/src/pages/views/components/JudgeScoreDisplay.tsx
+++ b/client/src/pages/views/components/JudgeScoreDisplay.tsx
@@ -3,20 +3,19 @@ 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'
 
 type ScoreDisplayProps = {
   teamIndex: number
+  activeSlide: RichSlide
 }
 
-const JudgeScoreDisplay = ({ teamIndex }: ScoreDisplayProps) => {
+const JudgeScoreDisplay = ({ teamIndex, activeSlide }: ScoreDisplayProps) => {
   const dispatch = useAppDispatch()
   const currentTeam = useAppSelector((state) => state.presentation.competition.teams[teamIndex])
   const currentCompetititonId = useAppSelector((state) => state.presentation.competition.id)
-  const activeQuestion = useAppSelector(
-    (state) =>
-      state.presentation.competition.slides.find((slide) => slide.id === state.presentation.slide?.id)?.questions[0]
-  )
+  const activeQuestion = activeSlide.questions[0]
   const scores = currentTeam.question_answers.map((questionAnswer) => questionAnswer.score)
   const questionMaxScore = activeQuestion?.total_score
   const activeAnswer = currentTeam.question_answers.find(
diff --git a/client/src/pages/views/components/JudgeScoringInstructions.tsx b/client/src/pages/views/components/JudgeScoringInstructions.tsx
index f8c21667..86d8eaf1 100644
--- a/client/src/pages/views/components/JudgeScoringInstructions.tsx
+++ b/client/src/pages/views/components/JudgeScoringInstructions.tsx
@@ -8,6 +8,7 @@ type JudgeScoringInstructionsProps = {
 }
 
 const JudgeScoringInstructions = ({ question }: JudgeScoringInstructionsProps) => {
+  console.log(question)
   return (
     <JudgeScoringInstructionsContainer elevation={3}>
       <ScoringInstructionsInner>
diff --git a/client/src/pages/views/components/PresentationComponent.tsx b/client/src/pages/views/components/PresentationComponent.tsx
index 0a688dc1..71783f6a 100644
--- a/client/src/pages/views/components/PresentationComponent.tsx
+++ b/client/src/pages/views/components/PresentationComponent.tsx
@@ -9,9 +9,10 @@ import TextComponentDisplay from '../../presentationEditor/components/TextCompon
 type PresentationComponentProps = {
   component: Component
   scale: number
+  currentSlideId?: number
 }
 
-const PresentationComponent = ({ component, scale }: PresentationComponentProps) => {
+const PresentationComponent = ({ component, scale, currentSlideId }: PresentationComponentProps) => {
   const renderInnerComponent = () => {
     switch (component.type_id) {
       case ComponentTypes.Text:
@@ -25,7 +26,7 @@ const PresentationComponent = ({ component, scale }: PresentationComponentProps)
           />
         )
       case ComponentTypes.Question:
-        return <QuestionComponentDisplay variant="presentation" />
+        return <QuestionComponentDisplay variant="presentation" currentSlideId={currentSlideId} />
       default:
         break
     }
diff --git a/client/src/pages/views/components/Timer.tsx b/client/src/pages/views/components/Timer.tsx
index 8d3b9f70..29f95349 100644
--- a/client/src/pages/views/components/Timer.tsx
+++ b/client/src/pages/views/components/Timer.tsx
@@ -1,10 +1,9 @@
 import React, { useEffect } from 'react'
-import { connect } from 'react-redux'
 import { setPresentationTimer, setPresentationTimerDecrement } from '../../../actions/presentation'
-import { useAppDispatch } from '../../../hooks'
+import { useAppDispatch, useAppSelector } from '../../../hooks'
 import store from '../../../store'
 
-const mapStateToProps = (state: any) => {
+/* const mapStateToProps = (state: any) => {
   return {
     timer: state.presentation.timer,
     timer_start_value: state.presentation.slide.timer,
@@ -15,28 +14,33 @@ const mapDispatchToProps = (dispatch: any) => {
   return {
     // tickTimer: () => dispatch(tickTimer(1)),
   }
-}
+} */
 
 let timerIntervalId: NodeJS.Timeout
 
-const Timer: React.FC = (props: any) => {
+const Timer: React.FC = () => {
   const dispatch = useAppDispatch()
-
+  const slide = store
+    .getState()
+    .presentation.competition.slides.find((slide) => slide.id === store.getState().presentation.activeSlideId)
+  const timerStartValue = slide?.timer
+  const timer = useAppSelector((state) => state.presentation.timer)
   useEffect(() => {
-    dispatch(setPresentationTimer({ enabled: false, value: store.getState().presentation.slide.timer }))
-  }, [props.timer_start_value])
+    if (!slide) return
+    dispatch(setPresentationTimer({ enabled: false, value: slide.timer }))
+  }, [timerStartValue])
 
   useEffect(() => {
-    if (props.timer.enabled) {
+    if (timer.enabled) {
       timerIntervalId = setInterval(() => {
         dispatch(setPresentationTimerDecrement())
       }, 1000)
     } else {
       clearInterval(timerIntervalId)
     }
-  }, [props.timer.enabled])
+  }, [timer.enabled])
 
-  return <div>{props.timer.value}</div>
+  return <div>{timer.value}</div>
 }
 
-export default connect(mapStateToProps, mapDispatchToProps)(Timer)
+export default Timer
diff --git a/client/src/reducers/editorReducer.ts b/client/src/reducers/editorReducer.ts
index 8aa14592..01a3fbea 100644
--- a/client/src/reducers/editorReducer.ts
+++ b/client/src/reducers/editorReducer.ts
@@ -45,6 +45,11 @@ export default function (state = initialState, action: AnyAction) {
         ...state,
         activeViewTypeId: action.payload as number,
       }
+    case Types.SET_EDITOR_LOADING:
+      return {
+        ...state,
+        loading: action.payload as boolean,
+      }
     default:
       return state
   }
diff --git a/client/src/reducers/presentationReducer.test.ts b/client/src/reducers/presentationReducer.test.ts
index 84f93684..e0368f7f 100644
--- a/client/src/reducers/presentationReducer.test.ts
+++ b/client/src/reducers/presentationReducer.test.ts
@@ -1,6 +1,4 @@
 import Types from '../actions/types'
-import { Slide } from '../interfaces/ApiModels'
-import { RichSlide } from '../interfaces/ApiRichModels'
 import presentationReducer from './presentationReducer'
 
 const initialState = {
@@ -13,14 +11,7 @@ const initialState = {
     year: 0,
     teams: [],
   },
-  slide: {
-    competition_id: 0,
-    background_image: undefined,
-    id: -1,
-    order: 0,
-    timer: 0,
-    title: '',
-  },
+  activeSlideId: -1,
   code: '',
   timer: {
     enabled: false,
@@ -50,138 +41,23 @@ it('should handle SET_PRESENTATION_COMPETITION', () => {
     })
   ).toEqual({
     competition: testCompetition,
-    slide: initialState.slide,
+    activeSlideId: initialState.activeSlideId,
     code: initialState.code,
     timer: initialState.timer,
   })
 })
 
-it('should handle SET_PRESENTATION_SLIDE', () => {
-  const testSlide = [
-    {
-      competition_id: 20,
-      id: 4,
-      order: 3,
-      timer: 123,
-      title: 'testSlideTitle',
-    },
-  ]
+it('should handle SET_PRESENTATION_SLIDE_ID', () => {
+  const testSlideId = 123123123
   expect(
     presentationReducer(initialState, {
-      type: Types.SET_PRESENTATION_SLIDE,
-      payload: testSlide,
+      type: Types.SET_PRESENTATION_SLIDE_ID,
+      payload: testSlideId,
     })
   ).toEqual({
     competition: initialState.competition,
-    slide: testSlide,
+    activeSlideId: testSlideId,
     code: initialState.code,
     timer: initialState.timer,
   })
 })
-
-describe('should handle SET_PRESENTATION_SLIDE_PREVIOUS', () => {
-  it('by changing slide to the previous if there is one', () => {
-    const testPresentationState = {
-      competition: {
-        ...initialState.competition,
-        slides: [
-          { competition_id: 0, order: 0 },
-          { competition_id: 0, order: 1 },
-        ] as RichSlide[],
-        teams: [],
-      },
-      slide: { competition_id: 0, order: 1 } as Slide,
-      code: initialState.code,
-      timer: initialState.timer,
-    }
-    expect(
-      presentationReducer(testPresentationState, {
-        type: Types.SET_PRESENTATION_SLIDE_PREVIOUS,
-      })
-    ).toEqual({
-      competition: testPresentationState.competition,
-      slide: testPresentationState.competition.slides[0],
-
-      code: initialState.code,
-      timer: initialState.timer,
-    })
-  })
-  it('by not changing slide if there is no previous one', () => {
-    const testPresentationState = {
-      competition: {
-        ...initialState.competition,
-        slides: [
-          { competition_id: 0, order: 0 },
-          { competition_id: 0, order: 1 },
-        ] as RichSlide[],
-        teams: [],
-      },
-      slide: { competition_id: 0, order: 0 } as Slide,
-      code: initialState.code,
-      timer: initialState.timer,
-    }
-    expect(
-      presentationReducer(testPresentationState, {
-        type: Types.SET_PRESENTATION_SLIDE_PREVIOUS,
-      })
-    ).toEqual({
-      competition: testPresentationState.competition,
-      slide: testPresentationState.competition.slides[0],
-      code: initialState.code,
-      timer: initialState.timer,
-    })
-  })
-})
-
-describe('should handle SET_PRESENTATION_SLIDE_NEXT', () => {
-  it('by changing slide to the next if there is one', () => {
-    const testPresentationState = {
-      competition: {
-        ...initialState.competition,
-        slides: [
-          { competition_id: 0, order: 0 },
-          { competition_id: 0, order: 1 },
-        ] as RichSlide[],
-        teams: [],
-      },
-      slide: { competition_id: 0, order: 0 } as Slide,
-      code: initialState.code,
-      timer: initialState.timer,
-    }
-    expect(
-      presentationReducer(testPresentationState, {
-        type: Types.SET_PRESENTATION_SLIDE_NEXT,
-      })
-    ).toEqual({
-      competition: testPresentationState.competition,
-      slide: testPresentationState.competition.slides[1],
-      code: initialState.code,
-      timer: initialState.timer,
-    })
-  })
-  it('by not changing slide if there is no next one', () => {
-    const testPresentationState = {
-      competition: {
-        ...initialState.competition,
-        slides: [
-          { competition_id: 0, order: 0 },
-          { competition_id: 0, order: 1 },
-        ] as RichSlide[],
-        teams: [],
-      },
-      slide: { competition_id: 0, order: 1 } as Slide,
-      code: initialState.code,
-      timer: initialState.timer,
-    }
-    expect(
-      presentationReducer(testPresentationState, {
-        type: Types.SET_PRESENTATION_SLIDE_NEXT,
-      })
-    ).toEqual({
-      competition: testPresentationState.competition,
-      slide: testPresentationState.competition.slides[1],
-      code: initialState.code,
-      timer: initialState.timer,
-    })
-  })
-})
diff --git a/client/src/reducers/presentationReducer.ts b/client/src/reducers/presentationReducer.ts
index 374baf32..4df814a8 100644
--- a/client/src/reducers/presentationReducer.ts
+++ b/client/src/reducers/presentationReducer.ts
@@ -1,13 +1,12 @@
 import { AnyAction } from 'redux'
 import Types from '../actions/types'
-import { Slide } from '../interfaces/ApiModels'
 import { Timer } from '../interfaces/Timer'
 import { RichCompetition } from './../interfaces/ApiRichModels'
 
 /** Define a type for the presentation state */
 interface PresentationState {
   competition: RichCompetition
-  slide: Slide
+  activeSlideId: number
   code: string
   timer: Timer
 }
@@ -23,14 +22,7 @@ const initialState: PresentationState = {
     teams: [],
     background_image: undefined,
   },
-  slide: {
-    competition_id: 0,
-    id: -1,
-    order: 0,
-    timer: 0,
-    title: '',
-    background_image: undefined,
-  },
+  activeSlideId: -1,
   code: '',
   timer: {
     enabled: false,
@@ -51,34 +43,11 @@ export default function (state = initialState, action: AnyAction) {
         ...state,
         code: action.payload,
       }
-    case Types.SET_PRESENTATION_SLIDE:
+    case Types.SET_PRESENTATION_SLIDE_ID:
       return {
         ...state,
-        slide: action.payload as Slide,
+        activeSlideId: action.payload as number,
       }
-    case Types.SET_PRESENTATION_SLIDE_PREVIOUS:
-      if (state.slide.order - 1 >= 0) {
-        return {
-          ...state,
-          slide: state.competition.slides[state.slide.order - 1],
-        }
-      }
-      return state
-    case Types.SET_PRESENTATION_SLIDE_NEXT:
-      if (state.slide.order + 1 < state.competition.slides.length) {
-        return {
-          ...state,
-          slide: state.competition.slides[state.slide.order + 1],
-        }
-      }
-      return state
-    case Types.SET_PRESENTATION_SLIDE_BY_ORDER:
-      if (0 <= action.payload && action.payload < state.competition.slides.length)
-        return {
-          ...state,
-          slide: state.competition.slides[action.payload],
-        }
-      return state
     case Types.SET_PRESENTATION_TIMER:
       if (action.payload.value == 0) {
         action.payload.enabled = false
diff --git a/client/src/sockets.ts b/client/src/sockets.ts
index 73a7e165..dabaf4b9 100644
--- a/client/src/sockets.ts
+++ b/client/src/sockets.ts
@@ -29,9 +29,9 @@ let socket: SocketIOClient.Socket
  * You can also comment functions, like usual. This will automatically appear
  * in the documentation, no more needed.
  */
-export const socketConnect = () => {
+export const socketConnect = (role: 'Judge' | 'Operator' | 'Team' | 'Audience') => {
   if (!socket) {
-    const token = localStorage.competitionToken
+    const token = localStorage[role]
     socket = io('localhost:5000', {
       transportOptions: {
         polling: {
@@ -43,7 +43,7 @@ export const socketConnect = () => {
     })
 
     socket.on('set_slide', (data: SetSlideInterface) => {
-      setCurrentSlideByOrder(data.slide_order)(store.dispatch)
+      setCurrentSlideByOrder(data.slide_order)(store.dispatch, store.getState)
     })
 
     socket.on('set_timer', (data: SetTimerInterface) => {
@@ -69,11 +69,19 @@ export const socketEndPresentation = () => {
 }
 
 export const socketSetSlideNext = () => {
-  socketSetSlide(store.getState().presentation.slide.order + 1) // TODO: Check that this slide exists
+  const activeSlide = store
+    .getState()
+    .presentation.competition.slides.find((slide) => slide.id === store.getState().presentation.activeSlideId)
+  if (!activeSlide) return
+  socketSetSlide(activeSlide.order + 1) // TODO: Check that this slide exists
 }
 
 export const socketSetSlidePrev = () => {
-  socketSetSlide(store.getState().presentation.slide.order - 1) // TODO: Check that this slide exists
+  const activeSlide = store
+    .getState()
+    .presentation.competition.slides.find((slide) => slide.id === store.getState().presentation.activeSlideId)
+  if (!activeSlide) return
+  socketSetSlide(activeSlide.order - 1) // TODO: Check that this slide exists
 }
 
 /**
diff --git a/client/src/utils/SecureRoute.tsx b/client/src/utils/SecureRoute.tsx
index 2b08b40c..64cb437a 100644
--- a/client/src/utils/SecureRoute.tsx
+++ b/client/src/utils/SecureRoute.tsx
@@ -21,7 +21,7 @@ const SecureRoute: React.FC<SecureRouteProps> = ({ component: Component, authLev
     if (authLevel === 'admin' || authLevel === 'login') {
       CheckAuthenticationAdmin().then(() => setInitialized(true))
     } else {
-      CheckAuthenticationCompetition().then(() => setInitialized(true))
+      CheckAuthenticationCompetition(authLevel).then(() => setInitialized(true))
     }
   }, [])
 
diff --git a/client/src/utils/checkAuthenticationCompetition.test.ts b/client/src/utils/checkAuthenticationCompetition.test.ts
index 0d0fdd90..478c4f5e 100644
--- a/client/src/utils/checkAuthenticationCompetition.test.ts
+++ b/client/src/utils/checkAuthenticationCompetition.test.ts
@@ -20,8 +20,8 @@ it('dispatches correct actions when auth token is ok', async () => {
 
   const testToken =
     'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjMyNTE0NDM2OTkzLCJ1c2VyX2NsYWltcyI6eyJjb21wZXRpdGlvbl9pZCI6MTIzMTIzLCJ0ZWFtX2lkIjozMjEzMjEsInZpZXciOiJQYXJ0aWNpcGFudCIsImNvZGUiOiJBQkNERUYifX0.1gPRJcjn3xuPOcgUUffMngIQDoDtxS9RZczcbdyyaaA'
-  localStorage.setItem('competitionToken', testToken)
-  await CheckAuthenticationCompetition()
+  localStorage.setItem('JudgeToken', testToken)
+  await CheckAuthenticationCompetition('Judge')
   expect(spy).toBeCalledWith({
     type: Types.SET_COMPETITION_LOGIN_DATA,
     payload: {
@@ -49,8 +49,8 @@ it('dispatches correct actions when getting user data fails', async () => {
   const spy = jest.spyOn(store, 'dispatch')
   const testToken =
     'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjMyNTE0NDM2OTkzLCJ1c2VyX2NsYWltcyI6eyJjb21wZXRpdGlvbl9pZCI6MTIzMTIzLCJ0ZWFtX2lkIjozMjEzMjEsInZpZXciOiJQYXJ0aWNpcGFudCIsImNvZGUiOiJBQkNERUYifX0.1gPRJcjn3xuPOcgUUffMngIQDoDtxS9RZczcbdyyaaA'
-  localStorage.setItem('competitionToken', testToken)
-  await CheckAuthenticationCompetition()
+  localStorage.setItem('AudienceToken', testToken)
+  await CheckAuthenticationCompetition('Audience')
   expect(spy).toBeCalledWith({ type: Types.SET_COMPETITION_LOGIN_UNAUTHENTICATED })
   expect(spy).toBeCalledTimes(1)
   expect(console.log).toHaveBeenCalled()
@@ -61,7 +61,7 @@ it('dispatches no actions when no token exists', async () => {
     return Promise.resolve({ data: {} })
   })
   const spy = jest.spyOn(store, 'dispatch')
-  await CheckAuthenticationCompetition()
+  await CheckAuthenticationCompetition('Operator')
   expect(spy).not.toBeCalled()
 })
 
@@ -71,9 +71,9 @@ it('dispatches correct actions when token is expired', async () => {
   })
   const testToken =
     'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MjAyMjE1OTgsImV4cCI6OTU3NTMzNTk4LCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIn0.uFXtkAsf-cTlKrTIdZ3E-gXnHkzS08iPrhS8iNCGV2E'
-  localStorage.setItem('competitionToken', testToken)
+  localStorage.setItem('TeamToken', testToken)
   const spy = jest.spyOn(store, 'dispatch')
-  await CheckAuthenticationCompetition()
+  await CheckAuthenticationCompetition('Team')
   expect(spy).toBeCalledWith({ type: Types.SET_COMPETITION_LOGIN_UNAUTHENTICATED })
   expect(spy).toBeCalledTimes(1)
 })
diff --git a/client/src/utils/checkAuthenticationCompetition.ts b/client/src/utils/checkAuthenticationCompetition.ts
index 4d542dc3..f6dfd8fe 100644
--- a/client/src/utils/checkAuthenticationCompetition.ts
+++ b/client/src/utils/checkAuthenticationCompetition.ts
@@ -5,12 +5,12 @@ import { getPresentationCompetition, setPresentationCode } from '../actions/pres
 import Types from '../actions/types'
 import store from '../store'
 
-const UnAuthorized = async () => {
-  await logoutCompetition()(store.dispatch)
+const UnAuthorized = async (role: 'Judge' | 'Operator' | 'Team' | 'Audience') => {
+  await logoutCompetition(role)(store.dispatch)
 }
 
-export const CheckAuthenticationCompetition = async () => {
-  const authToken = localStorage.competitionToken
+export const CheckAuthenticationCompetition = async (role: 'Judge' | 'Operator' | 'Team' | 'Audience') => {
+  const authToken = localStorage[`${role}Token`]
   if (authToken) {
     const decodedToken: any = jwtDecode(authToken)
     if (decodedToken.exp * 1000 >= Date.now()) {
@@ -31,10 +31,10 @@ export const CheckAuthenticationCompetition = async () => {
         })
         .catch((error) => {
           console.log(error)
-          UnAuthorized()
+          UnAuthorized(role)
         })
     } else {
-      await UnAuthorized()
+      await UnAuthorized(role)
     }
   }
 }
-- 
GitLab