Skip to content
Snippets Groups Projects
Commit 7ef2d370 authored by Max Rüdiger's avatar Max Rüdiger
Browse files

139 operator view

parent 0b78e58d
No related branches found
No related tags found
1 merge request!104139 operator view
Pipeline #42836 passed with warnings
......@@ -7,8 +7,8 @@ import LoginPage from './pages/login/LoginPage'
import PresentationEditorPage from './pages/presentationEditor/PresentationEditorPage'
import AudienceViewPage from './pages/views/AudienceViewPage'
import JudgeViewPage from './pages/views/JudgeViewPage'
import ParticipantViewPage from './pages/views/ParticipantViewPage'
import PresenterViewPage from './pages/views/PresenterViewPage'
import TeamViewPage from './pages/views/TeamViewPage'
import OperatorViewPage from './pages/views/OperatorViewPage'
import ViewSelectPage from './pages/views/ViewSelectPage'
import SecureRoute from './utils/SecureRoute'
......@@ -24,8 +24,8 @@ const Main: React.FC = () => {
<SecureRoute path="/admin" component={AdminPage} />
<SecureRoute path="/editor/competition-id=:competitionId" component={PresentationEditorPage} />
<Route exact path="/:code" component={ViewSelectPage} />
<Route exact path="/participant/id=:id&code=:code" component={ParticipantViewPage} />
<SecureRoute exact path="/presenter/id=:id&code=:code" component={PresenterViewPage} />
<Route exact path="/team/id=:id&code=:code" component={TeamViewPage} />
<SecureRoute exact path="/operator/id=:id&code=:code" component={OperatorViewPage} />
<Route exact path="/judge/id=:id&code=:code" component={JudgeViewPage} />
<Route exact path="/audience/id=:id&code=:code" component={AudienceViewPage} />
</Switch>
......
......@@ -94,7 +94,7 @@ const CompetitionManager: React.FC = (props: any) => {
}
const handleStartCompetition = () => {
history.push(`/presenter/id=${activeId}&code=123123`)
history.push(`/operator/id=${activeId}&code=123123`)
console.log('GLHF!')
}
......
......@@ -4,7 +4,7 @@ import React from 'react'
import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom'
import store from '../../store'
import PresenterViewPage from './PresenterViewPage'
import OperatorViewPage from './OperatorViewPage'
it('renders presenter view page', () => {
const compRes: any = {
......@@ -36,7 +36,7 @@ it('renders presenter view page', () => {
render(
<BrowserRouter>
<Provider store={store}>
<PresenterViewPage />
<OperatorViewPage />
</Provider>
</BrowserRouter>
)
......
......@@ -7,6 +7,7 @@ import {
DialogTitle,
List,
ListItem,
ListItemText,
Popover,
Tooltip,
Typography,
......@@ -14,6 +15,8 @@ import {
useTheme,
} from '@material-ui/core'
import AssignmentIcon from '@material-ui/icons/Assignment'
import FileCopyIcon from '@material-ui/icons/FileCopy'
import SupervisorAccountIcon from '@material-ui/icons/SupervisorAccount'
import BackspaceIcon from '@material-ui/icons/Backspace'
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft'
import ChevronRightIcon from '@material-ui/icons/ChevronRight'
......@@ -36,23 +39,39 @@ import SlideDisplay from '../presentationEditor/components/SlideDisplay'
import PresentationComponent from './components/PresentationComponent'
import Timer from './components/Timer'
import {
PresenterButton,
PresenterContainer,
PresenterContent,
PresenterFooter,
PresenterHeader,
PresenterInnerContent,
OperatorButton,
OperatorContainer,
OperatorFooter,
OperatorHeader,
OperatorContent,
OperatorInnerContent,
SlideCounter,
ToolBarContainer,
} from './styled'
/**
* Description:
*
* Presentation is an active competition
*
*
* ===========================================
* TODO:
* - Instead of copying code for others to join the competition, copy URL.
*
* - Make code popup less code by using .map instead
*
* - Fix scoreboard
*
* - When two userers are connected to the same Localhost:5000 and updates/starts/end competition it
* creates a bug where the competition can't be started.
* ===========================================
*/
const PresenterViewPage: React.FC = () => {
const OperatorViewPage: React.FC = () => {
// for dialog alert
const [openAlert, setOpen] = React.useState(false)
const [openAlertCode, setOpenCode] = React.useState(true)
const theme = useTheme()
const fullScreen = useMediaQuery(theme.breakpoints.down('sm'))
const teams = useAppSelector((state) => state.presentation.competition.teams)
......@@ -62,14 +81,14 @@ const PresenterViewPage: React.FC = () => {
const history = useHistory()
const dispatch = useAppDispatch()
const viewTypes = useAppSelector((state) => state.types.viewTypes)
const activeViewTypeId = viewTypes.find((viewType) => viewType.name === 'Presenter')?.id
const activeViewTypeId = viewTypes.find((viewType) => viewType.name === 'Operator')?.id
useEffect(() => {
dispatch(getPresentationCompetition(id))
dispatch(setPresentationCode(code))
socket_connect()
socketSetSlide // Behövs denna?
setTimeout(startCompetition, 500) // Ghetto, wait for everything to load
setTimeout(startCompetition, 1000) // Ghetto, wait for everything to load
// console.log(id)
}, [])
......@@ -79,6 +98,7 @@ const PresenterViewPage: React.FC = () => {
const handleClose = () => {
setOpen(false)
setOpenCode(false)
setAnchorEl(null)
}
......@@ -92,6 +112,14 @@ const PresenterViewPage: React.FC = () => {
setOpen(true)
}
const handleOpenCodes = () => {
setOpenCode(true)
}
const handleCopy = () => {
console.log('copied code to clipboard')
}
const endCompetition = () => {
setOpen(false)
socketEndPresentation()
......@@ -100,12 +128,66 @@ const PresenterViewPage: React.FC = () => {
}
return (
<PresenterContainer>
<PresenterHeader>
<OperatorContainer>
<Dialog
fullScreen={fullScreen}
open={openAlertCode}
onClose={handleClose}
aria-labelledby="responsive-dialog-title"
>
<DialogTitle id="responsive-dialog-title">{'Koder för tävlingen'}</DialogTitle>
<DialogContent>
<DialogContentText>
<ListItem>
<ListItemText primary={`Domare: ${presentation.code}`} />
<Tooltip title="Kopiera kod" arrow>
<Button
onClick={() => {
navigator.clipboard.writeText(presentation.code)
}}
>
<FileCopyIcon fontSize="small" />
</Button>
</Tooltip>
</ListItem>
<ListItem>
<ListItemText primary={`Tävlande: ${presentation.code}`} />
<Tooltip title="Kopiera kod" arrow>
<Button
onClick={() => {
navigator.clipboard.writeText(presentation.code)
}}
>
<FileCopyIcon fontSize="small" />
</Button>
</Tooltip>
</ListItem>
<ListItem>
<ListItemText primary={`Publik: ${presentation.code}`} />
<Tooltip title="Kopiera kod" arrow>
<Button
onClick={() => {
navigator.clipboard.writeText(presentation.code)
}}
>
<FileCopyIcon fontSize="small" />
</Button>
</Tooltip>
</ListItem>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleClose} color="primary">
Ok
</Button>
</DialogActions>
</Dialog>
<OperatorHeader>
<Tooltip title="Avsluta tävling" arrow>
<PresenterButton onClick={handleVerifyExit} variant="contained" color="secondary">
<OperatorButton onClick={handleVerifyExit} variant="contained" color="secondary">
<BackspaceIcon fontSize="large" />
</PresenterButton>
</OperatorButton>
</Tooltip>
<Dialog
......@@ -135,67 +217,73 @@ const PresenterViewPage: React.FC = () => {
{presentation.slide.order + 1} / {presentation.competition.slides.length}
</Typography>
</SlideCounter>
</PresenterHeader>
</OperatorHeader>
<div style={{ height: 0, paddingTop: 120 }} />
<PresenterContent>
<PresenterInnerContent>
<OperatorContent>
<OperatorInnerContent>
{activeViewTypeId && <SlideDisplay variant="presentation" activeViewTypeId={activeViewTypeId} />}
</PresenterInnerContent>
</PresenterContent>
</OperatorInnerContent>
</OperatorContent>
<div style={{ height: 0, paddingTop: 140 }} />
<PresenterFooter>
<OperatorFooter>
<ToolBarContainer>
<Tooltip title="Previous Slide" arrow>
<PresenterButton onClick={socketSetSlidePrev} variant="contained">
<Tooltip title="Föregående" arrow>
<OperatorButton onClick={socketSetSlidePrev} variant="contained">
<ChevronLeftIcon fontSize="large" />
</PresenterButton>
</OperatorButton>
</Tooltip>
{/*
// Manual start button
<Tooltip title="Start Presentation" arrow>
<PresenterButton onClick={startCompetition} variant="contained">
<OperatorButton onClick={startCompetition} variant="contained">
start
</PresenterButton>
</OperatorButton>
</Tooltip>
// This creates a join button, but presenter should not join others, others should join presenter
// This creates a join button, but Operator should not join others, others should join Operator
<Tooltip title="Join Presentation" arrow>
<PresenterButton onClick={socketJoinPresentation} variant="contained">
<OperatorButton onClick={socketJoinPresentation} variant="contained">
<GroupAddIcon fontSize="large" />
</PresenterButton>
</OperatorButton>
</Tooltip>
// This creates another end button, it might not be needed since we already have one
<Tooltip title="End Presentation" arrow>
<PresenterButton onClick={socketEndPresentation} variant="contained">
<OperatorButton onClick={socketEndPresentation} variant="contained">
<CancelIcon fontSize="large" />
</PresenterButton>
</OperatorButton>
</Tooltip>
*/}
<Tooltip title="Start Timer" arrow>
<PresenterButton onClick={socketStartTimer} variant="contained">
<Tooltip title="Starta Timer" arrow>
<OperatorButton onClick={socketStartTimer} variant="contained">
<TimerIcon fontSize="large" />
<Timer></Timer>
</PresenterButton>
</OperatorButton>
</Tooltip>
<Tooltip title="Scoreboard" arrow>
<PresenterButton onClick={handleOpenPopover} variant="contained">
<Tooltip title="Ställning" arrow>
<OperatorButton onClick={handleOpenPopover} variant="contained">
<AssignmentIcon fontSize="large" />
</PresenterButton>
</OperatorButton>
</Tooltip>
<Tooltip title="Next Slide" arrow>
<PresenterButton onClick={socketSetSlideNext} variant="contained">
<Tooltip title="Koder" arrow>
<OperatorButton onClick={handleOpenCodes} variant="contained">
<SupervisorAccountIcon fontSize="large" />
</OperatorButton>
</Tooltip>
<Tooltip title="Nästa" arrow>
<OperatorButton onClick={socketSetSlideNext} variant="contained">
<ChevronRightIcon fontSize="large" />
</PresenterButton>
</OperatorButton>
</Tooltip>
</ToolBarContainer>
</PresenterFooter>
</OperatorFooter>
<Popover
open={Boolean(anchorEl)}
anchorEl={anchorEl}
......@@ -210,17 +298,15 @@ const PresenterViewPage: React.FC = () => {
}}
>
<List>
{/** TODO:
* Fix scoreboard
*/}
{teams && teams.map((team) => <ListItem key={team.id}>{team.name} score: 20</ListItem>)}
{teams.map((team) => (
<ListItem key={team.id}>
{team.name} score: {team.question_answers}{' '}
</ListItem>
))}
</List>
</Popover>
</PresenterContainer>
</OperatorContainer>
)
}
export default PresenterViewPage
function componentDidMount() {
throw new Error('Function not implemented.')
}
export default OperatorViewPage
......@@ -3,7 +3,7 @@ import React from 'react'
import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom'
import store from '../../store'
import ParticipantViewPage from './ParticipantViewPage'
import TeamViewPage from './TeamViewPage'
import mockedAxios from 'axios'
it('renders participant view page', () => {
......@@ -16,7 +16,7 @@ it('renders participant view page', () => {
render(
<BrowserRouter>
<Provider store={store}>
<ParticipantViewPage />
<TeamViewPage />
</Provider>
</BrowserRouter>
)
......
......@@ -2,28 +2,28 @@ import React, { useEffect } from 'react'
import PresentationComponent from './components/PresentationComponent'
import { useHistory } from 'react-router-dom'
import SlideDisplay from '../presentationEditor/components/SlideDisplay'
import { ParticipantContainer } from './styled'
import { TeamContainer } from './styled'
import { socketJoinPresentation, socket_connect } from '../../sockets'
import { useAppSelector } from '../../hooks'
const ParticipantViewPage: React.FC = () => {
const TeamViewPage: React.FC = () => {
const history = useHistory()
const code = useAppSelector((state) => state.presentation.code)
const viewTypes = useAppSelector((state) => state.types.viewTypes)
const activeViewTypeId = viewTypes.find((viewType) => viewType.name === 'Participant')?.id
const activeViewTypeId = viewTypes.find((viewType) => viewType.name === 'Team')?.id
useEffect(() => {
//hides the url so people can't sneak peak
history.push('participant')
history.push('team')
if (code && code !== '') {
socket_connect()
socketJoinPresentation()
}
}, [])
return (
<ParticipantContainer>
<TeamContainer>
{activeViewTypeId && <SlideDisplay variant="presentation" activeViewTypeId={activeViewTypeId} />}
</ParticipantContainer>
</TeamContainer>
)
}
export default ParticipantViewPage
export default TeamViewPage
......@@ -4,9 +4,9 @@ import { Link, useRouteMatch } from 'react-router-dom'
import { ViewSelectButtonGroup, ViewSelectContainer } from './styled'
import { useParams } from 'react-router-dom'
import { CircularProgress, Typography } from '@material-ui/core'
import ParticipantViewPage from './ParticipantViewPage'
import TeamViewPage from './TeamViewPage'
import axios from 'axios'
import PresenterViewPage from './PresenterViewPage'
import OperatorViewPage from './OperatorViewPage'
import JudgeViewPage from './JudgeViewPage'
import AudienceViewPage from './AudienceViewPage'
import { useAppDispatch, useAppSelector } from '../../hooks'
......@@ -29,7 +29,7 @@ const ViewSelectPage: React.FC = () => {
if (competitionId) {
switch (viewType) {
case 'Team':
return <ParticipantViewPage />
return <TeamViewPage />
case 'Judge':
return <JudgeViewPage code={code} competitionId={competitionId} />
case 'Audience':
......
......@@ -35,7 +35,7 @@ export const ViewSelectButtonGroup = styled.div`
margin-right: auto;
`
export const PresenterHeader = styled.div`
export const OperatorHeader = styled.div`
display: flex;
justify-content: space-between;
height: 120px;
......@@ -43,7 +43,7 @@ export const PresenterHeader = styled.div`
position: absolute;
`
export const PresenterFooter = styled.div`
export const OperatorFooter = styled.div`
display: flex;
justify-content: space-between;
height: 140px;
......@@ -52,7 +52,7 @@ export const PresenterFooter = styled.div`
width: 100%;
`
export const PresenterButton = styled(Button)`
export const OperatorButton = styled(Button)`
width: 100px;
height: 100px;
margin-left: 16px;
......@@ -66,7 +66,7 @@ export const SlideCounter = styled(Button)`
margin-top: 16px;
`
export const PresenterContainer = styled.div`
export const OperatorContainer = styled.div`
display: flex;
flex-direction: column;
justify-content: space-between;
......@@ -127,7 +127,7 @@ export const InnerContent = styled.div`
max-width: calc(((100vh - 64px) / 9) * 16);
`
export const PresenterContent = styled.div`
export const OperatorContent = styled.div`
height: 100%;
width: 100%;
display: flex;
......@@ -135,7 +135,7 @@ export const PresenterContent = styled.div`
background-color: rgba(0, 0, 0, 0.08);
`
export const PresenterInnerContent = styled.div`
export const OperatorInnerContent = styled.div`
height: 100%;
width: 100%;
/* Makes sure width is not bigger than where a 16:9 display can fit
......@@ -143,7 +143,7 @@ export const PresenterInnerContent = styled.div`
max-width: calc(((100vh - 260px) / 9) * 16);
`
export const ParticipantContainer = styled.div`
export const TeamContainer = styled.div`
max-width: calc((100vh / 9) * 16);
`
......
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