From 6afcf518f87ce31388710ae27201293acf4c3612 Mon Sep 17 00:00:00 2001
From: Albin Henriksson <albhe428@student.liu.se>
Date: Tue, 18 May 2021 06:58:56 +0000
Subject: [PATCH] Resolve "Fix window reload in operator view"

---
 .../components/SlideDisplay.tsx               |  4 +-
 .../presentationEditor/components/Teams.tsx   | 74 ++++++++++++-------
 .../presentationEditor/components/styled.tsx  | 10 +--
 client/src/pages/views/OperatorViewPage.tsx   | 44 ++++++-----
 client/src/pages/views/components/Timer.tsx   |  2 +-
 5 files changed, 80 insertions(+), 54 deletions(-)

diff --git a/client/src/pages/presentationEditor/components/SlideDisplay.tsx b/client/src/pages/presentationEditor/components/SlideDisplay.tsx
index da5bb92f..897a321c 100644
--- a/client/src/pages/presentationEditor/components/SlideDisplay.tsx
+++ b/client/src/pages/presentationEditor/components/SlideDisplay.tsx
@@ -59,11 +59,11 @@ const SlideDisplay = ({ variant, activeViewTypeId, currentSlideId }: SlideDispla
     <SlideEditorContainer>
       <SlideEditorContainerRatio>
         <SlideEditorPaper ref={editorPaperRef}>
-          <SlideDisplayText scale={scale}>
+          <SlideDisplayText $scale={scale}>
             {variant === 'editor' && slide?.timer ? `Tid kvar: ${slide?.timer}` : ''}
             {variant === 'presentation' && <Timer />}
           </SlideDisplayText>
-          <SlideDisplayText scale={scale} right>
+          <SlideDisplayText $scale={scale} $right>
             {slide && `Sida: ${slide?.order + 1} / ${totalSlides}`}
           </SlideDisplayText>
           {(competitionBackgroundImage || slideBackgroundImage) && (
diff --git a/client/src/pages/presentationEditor/components/Teams.tsx b/client/src/pages/presentationEditor/components/Teams.tsx
index 564dbc84..c764910a 100644
--- a/client/src/pages/presentationEditor/components/Teams.tsx
+++ b/client/src/pages/presentationEditor/components/Teams.tsx
@@ -5,17 +5,25 @@ import {
   DialogContent,
   DialogContentText,
   DialogTitle,
+  IconButton,
   ListItem,
   ListItemText,
   TextField,
 } from '@material-ui/core'
+import CloseIcon from '@material-ui/icons/Close'
+import EditIcon from '@material-ui/icons/Edit'
 import axios from 'axios'
 import React, { useState } from 'react'
 import { getEditorCompetition } from '../../../actions/editor'
 import { useAppDispatch, useAppSelector } from '../../../hooks'
-import { Center, Clickable } from './styled'
-import { AddButton, SettingsList } from './styled'
-import CloseIcon from '@material-ui/icons/Close'
+import { RichTeam } from '../../../interfaces/ApiRichModels'
+import { AddButton, Center, SettingsList } from './styled'
+
+interface TeamEditState {
+  open: boolean
+  variant?: 'Edit' | 'Add'
+  team?: RichTeam
+}
 
 type TeamsProps = {
   competitionId: string
@@ -24,23 +32,26 @@ type TeamsProps = {
 const Teams = ({ competitionId }: TeamsProps) => {
   const dispatch = useAppDispatch()
   const competition = useAppSelector((state) => state.editor.competition)
-  const addTeam = async () => {
-    setAddTeamOpen(false)
-    await axios
-      .post(`/api/competitions/${competitionId}/teams`, { name: selectedTeamName })
-      .then(() => {
-        dispatch(getEditorCompetition(competitionId))
-      })
-      .catch(console.log)
+  const editTeam = async () => {
+    if (editTeamState.variant === 'Add') {
+      await axios
+        .post(`/api/competitions/${competitionId}/teams`, { name: selectedTeamName })
+        .then(() => {
+          dispatch(getEditorCompetition(competitionId))
+        })
+        .catch(console.log)
+    } else if (editTeamState.team) {
+      await axios
+        .put(`/api/competitions/${competitionId}/teams/${editTeamState.team.id}`, { name: selectedTeamName })
+        .then(() => {
+          dispatch(getEditorCompetition(competitionId))
+        })
+        .catch(console.log)
+    }
+    setEditTeamState({ open: false })
   }
   // For "add team" dialog
-  const [addTeamOpen, setAddTeamOpen] = useState(false)
-  const openAddTeam = () => {
-    setAddTeamOpen(true)
-  }
-  const closeAddTeam = () => {
-    setAddTeamOpen(false)
-  }
+  const [editTeamState, setEditTeamState] = useState<TeamEditState>({ open: false })
   let selectedTeamName = ''
   const updateSelectedTeamName = (event: React.ChangeEvent<{ value: string }>) => {
     selectedTeamName = event.target.value
@@ -67,28 +78,37 @@ const Teams = ({ competitionId }: TeamsProps) => {
           <div key={team.id}>
             <ListItem divider>
               <ListItemText primary={team.name} />
-              <Clickable>
-                <CloseIcon onClick={() => removeTeam(team.id)} />
-              </Clickable>
+              <IconButton size="small" onClick={() => setEditTeamState({ variant: 'Edit', open: true, team })}>
+                <EditIcon />
+              </IconButton>
+              <IconButton size="small" onClick={() => removeTeam(team.id)}>
+                <CloseIcon />
+              </IconButton>
             </ListItem>
           </div>
         ))}
-      <ListItem button onClick={openAddTeam}>
+      <ListItem button onClick={() => setEditTeamState({ variant: 'Add', open: true })}>
         <Center>
           <AddButton variant="button">Lägg till lag</AddButton>
         </Center>
       </ListItem>
-      <Dialog open={addTeamOpen} onClose={closeAddTeam}>
-        <DialogTitle>Lägg till lag</DialogTitle>
+      <Dialog open={editTeamState.open} onClose={() => setEditTeamState({ open: false })}>
+        <DialogTitle>
+          {editTeamState.variant === 'Edit' && editTeamState.team
+            ? `Redigera lagnamn för lag ${editTeamState.team.name}`
+            : 'Lägg till lag'}
+        </DialogTitle>
         <DialogContent>
-          <DialogContentText>Skriv namnet på laget och klicka sedan på bekräfta.</DialogContentText>
+          <DialogContentText>
+            Skriv {editTeamState.variant === 'Edit' ? 'det nya' : ''} namnet på laget och klicka sedan på bekräfta.
+          </DialogContentText>
           <TextField autoFocus margin="dense" label="Lagnamn" fullWidth onChange={updateSelectedTeamName} />
         </DialogContent>
         <DialogActions>
-          <Button onClick={closeAddTeam} color="secondary">
+          <Button onClick={() => setEditTeamState({ open: false })} color="secondary">
             Avbryt
           </Button>
-          <Button onClick={addTeam} color="primary">
+          <Button onClick={editTeam} color="primary">
             Bekräfta
           </Button>
         </DialogActions>
diff --git a/client/src/pages/presentationEditor/components/styled.tsx b/client/src/pages/presentationEditor/components/styled.tsx
index e46fc8b9..1a4f9169 100644
--- a/client/src/pages/presentationEditor/components/styled.tsx
+++ b/client/src/pages/presentationEditor/components/styled.tsx
@@ -147,14 +147,14 @@ export const SettingsItemContainer = styled.div`
 `
 
 interface SlideDisplayTextProps {
-  scale: number
-  right?: boolean
+  $scale: number
+  $right?: boolean
 }
 
 export const SlideDisplayText = styled(Typography)<SlideDisplayTextProps>`
   position: absolute;
   top: 5px;
-  left: ${(props) => (props.right ? undefined : 5)}px;
-  right: ${(props) => (props.right ? 5 : undefined)}px;
-  font-size: ${(props) => 24 * props.scale}px;
+  left: ${(props) => (props.$right ? undefined : 5)}px;
+  right: ${(props) => (props.$right ? 5 : undefined)}px;
+  font-size: ${(props) => 24 * props.$scale}px;
 `
diff --git a/client/src/pages/views/OperatorViewPage.tsx b/client/src/pages/views/OperatorViewPage.tsx
index a3bd2efd..e0544902 100644
--- a/client/src/pages/views/OperatorViewPage.tsx
+++ b/client/src/pages/views/OperatorViewPage.tsx
@@ -27,7 +27,8 @@ import { Alert } from '@material-ui/lab'
 import axios from 'axios'
 import React, { useEffect, useState } from 'react'
 import { useHistory } from 'react-router-dom'
-import { useAppSelector } from '../../hooks'
+import { logoutCompetition } from '../../actions/competitionLogin'
+import { useAppDispatch, useAppSelector } from '../../hooks'
 import { socketConnect, socketEndPresentation, socketSync } from '../../sockets'
 import SlideDisplay from '../presentationEditor/components/SlideDisplay'
 import { Center } from '../presentationEditor/components/styled'
@@ -89,7 +90,7 @@ const OperatorViewPage: React.FC = () => {
   const competitionName = useAppSelector((state) => state.presentation.competition.name)
 
   //const fullScreen = useMediaQuery(theme.breakpoints.down('sm'))
-
+  const dispatch = useAppDispatch()
   const classes = useStyles()
   const teams = useAppSelector((state) => state.presentation.competition.teams)
   const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null)
@@ -140,8 +141,7 @@ const OperatorViewPage: React.FC = () => {
   const endCompetition = () => {
     setOpen(false)
     socketEndPresentation()
-    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
+    dispatch(logoutCompetition('Operator'))
   }
 
   const getCodes = async () => {
@@ -287,22 +287,26 @@ const OperatorViewPage: React.FC = () => {
       {<div style={{ minHeight: 128 }} />}
       <OperatorFooter position="fixed">
         <Tooltip title="Föregående sida" arrow>
-          <OperatorButton onClick={handleSetPrevSlide} variant="contained" disabled={isFirstSlide} color="primary">
-            <ChevronLeftIcon fontSize="large" />
-          </OperatorButton>
+          <div>
+            <OperatorButton onClick={handleSetPrevSlide} variant="contained" disabled={isFirstSlide} color="primary">
+              <ChevronLeftIcon fontSize="large" />
+            </OperatorButton>
+          </div>
         </Tooltip>
 
         {slideTimer !== null && (
           <Tooltip title="Starta timer" arrow>
-            <OperatorButton
-              onClick={handleStartTimer}
-              variant="contained"
-              disabled={timer.value !== null && !timer.enabled}
-              color="primary"
-            >
-              <TimerIcon fontSize="large" />
-              <Timer disableText />
-            </OperatorButton>
+            <div>
+              <OperatorButton
+                onClick={handleStartTimer}
+                variant="contained"
+                disabled={timer.value !== null && !timer.enabled}
+                color="primary"
+              >
+                <TimerIcon fontSize="large" />
+                <Timer disableText />
+              </OperatorButton>
+            </div>
           </Tooltip>
         )}
 
@@ -320,9 +324,11 @@ const OperatorViewPage: React.FC = () => {
         </Tooltip>
 
         <Tooltip title="Nästa sida" arrow>
-          <OperatorButton onClick={handleSetNextSlide} variant="contained" disabled={isLastSlide} color="primary">
-            <ChevronRightIcon fontSize="large" />
-          </OperatorButton>
+          <div>
+            <OperatorButton onClick={handleSetNextSlide} variant="contained" disabled={isLastSlide} color="primary">
+              <ChevronRightIcon fontSize="large" />
+            </OperatorButton>
+          </div>
         </Tooltip>
       </OperatorFooter>
 
diff --git a/client/src/pages/views/components/Timer.tsx b/client/src/pages/views/components/Timer.tsx
index e04c8bc1..6f4add03 100644
--- a/client/src/pages/views/components/Timer.tsx
+++ b/client/src/pages/views/components/Timer.tsx
@@ -50,7 +50,7 @@ const Timer = ({ disableText }: TimerProps) => {
     )
   }, [timer.enabled, slideTimer])
 
-  return <div>{`${!disableText ? 'Tid kvar:' : ''} ${Math.round(remainingTimer / 1000)}`}</div>
+  return <>{`${!disableText ? 'Tid kvar:' : ''} ${Math.round(remainingTimer / 1000)}`}</>
 }
 
 export default Timer
-- 
GitLab