Skip to content
Snippets Groups Projects
Commit eb09fc46 authored by robban64's avatar robban64
Browse files

Merge branch 'dev' of...

Merge branch 'dev' of https://gitlab.liu.se/tddd96-grupp11/teknikattan-scoring-system into 157-whitelist-jwt
parents 14648c60 a29a04ba
No related branches found
No related tags found
1 merge request!121Resolve "Whitelist jwt"
Pipeline #43125 passed
Showing
with 232 additions and 168 deletions
......@@ -5,7 +5,7 @@
"editor.tabCompletion": "on",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.organizeImports": false
"source.organizeImports": true
},
//python
"python.venvPath": "${workspaceFolder}\\server",
......
......@@ -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 TeamViewPage from './pages/views/TeamViewPage'
import OperatorViewPage from './pages/views/OperatorViewPage'
import TeamViewPage from './pages/views/TeamViewPage'
import ViewSelectPage from './pages/views/ViewSelectPage'
import SecureRoute from './utils/SecureRoute'
......@@ -20,14 +20,38 @@ const Main: React.FC = () => {
return (
<BrowserRouter>
<Switch>
<SecureRoute login exact path="/" component={LoginPage} />
<SecureRoute path="/admin" component={AdminPage} />
<SecureRoute path="/editor/competition-id=:competitionId" component={PresentationEditorPage} />
<SecureRoute authLevel="login" exact path="/" component={LoginPage} />
<SecureRoute authLevel="admin" path="/admin" component={AdminPage} />
<SecureRoute
authLevel="admin"
path="/editor/competition-id=:competitionId"
component={PresentationEditorPage}
/>
<Route exact path="/:code" component={ViewSelectPage} />
<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} />
<SecureRoute
authLevel="competition"
exact
path="/team/competition-id=:competitionId"
component={TeamViewPage}
/>
<SecureRoute
authLevel="competition"
exact
path="/operator/competition-id=:competitionId"
component={OperatorViewPage}
/>
<SecureRoute
authLevel="competition"
exact
path="/judge/competition-id=:competitionId"
component={JudgeViewPage}
/>
<SecureRoute
authLevel="competition"
exact
path="/audience/competition-id=:competitionId"
component={AudienceViewPage}
/>
</Switch>
</BrowserRouter>
)
......
......@@ -5,19 +5,29 @@ This file handles actions for the competitionLogin redux state
import axios from 'axios'
import { History } from 'history'
import { AppDispatch } from '../store'
import { AccountLoginModel } from './../interfaces/FormModels'
import Types from './types'
// Action creator to attempt to login with competition code
export const loginCompetition = (code: string, history: History) => async (dispatch: AppDispatch) => {
export const loginCompetition = (code: string, history: History, redirect: boolean) => async (
dispatch: AppDispatch
) => {
dispatch({ type: Types.LOADING_COMPETITION_LOGIN })
await axios
.post('/api/auth/login/code', { code })
.then((res) => {
console.log(code, res.data[0])
const token = `Bearer ${res.data.access_token}`
localStorage.setItem('competitionToken', 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
// history.push('/admin') //redirecting to admin page after login success
if (res.data && res.data[0] && res.data[0].view_type_id) {
dispatch({
type: Types.SET_COMPETITION_LOGIN_DATA,
payload: {
competition_id: res.data.competition_id,
team_id: res.data.team_id,
view: res.data.view,
},
})
if (redirect && res.data && res.data.view_type_id) {
history.push(`/${code}`)
}
})
......@@ -26,3 +36,15 @@ export const loginCompetition = (code: string, history: History) => async (dispa
console.log(err)
})
}
// Log out from competition and remove jwt token from local storage and axios
export const logoutCompetition = () => async (dispatch: AppDispatch) => {
localStorage.removeItem('competitionToken')
await axios.post('/api/auth/logout').then(() => {
delete axios.defaults.headers.common['Authorization']
dispatch({
type: Types.SET_COMPETITION_LOGIN_UNAUTHENTICATED,
})
window.location.href = '/' //redirect to login page
})
}
......@@ -14,6 +14,9 @@ export default {
SET_SEARCH_USERS_TOTAL_COUNT: 'SET_SEARCH_USERS_TOTAL_COUNT',
SET_ERRORS: 'SET_ERRORS',
CLEAR_ERRORS: 'CLEAR_ERRORS',
SET_COMPETITION_LOGIN_DATA: 'SET_COMPETITION_LOGIN_DATA',
SET_COMPETITION_LOGIN_AUTHENTICATED: 'SET_COMPETITION_LOGIN_AUTHENTICATED',
SET_COMPETITION_LOGIN_UNAUTHENTICATED: 'SET_COMPETITION_LOGIN_UNAUTHENTICATED',
SET_COMPETITION_LOGIN_ERRORS: 'SET_COMPETITION_LOGIN_ERRORS',
CLEAR_COMPETITION_LOGIN_ERRORS: 'CLEAR_COMPETITION_LOGIN_ERRORS',
SET_UNAUTHENTICATED: 'SET_UNAUTHENTICATED',
......
export interface ViewParams {
id: string
code: string
competitionId: string
}
......@@ -16,7 +16,6 @@ import ExitToAppIcon from '@material-ui/icons/ExitToApp'
import LocationCityIcon from '@material-ui/icons/LocationCity'
import PeopleIcon from '@material-ui/icons/People'
import SettingsOverscanIcon from '@material-ui/icons/SettingsOverscan'
import axios from 'axios'
import React, { useEffect } from 'react'
import { Link, Route, Switch, useRouteMatch } from 'react-router-dom'
import { getCities } from '../../actions/cities'
......
import { Button, TextField, Typography } from '@material-ui/core'
import { Alert, AlertTitle } from '@material-ui/lab'
import axios from 'axios'
import { Formik, FormikHelpers } from 'formik'
import { Formik } from 'formik'
import React from 'react'
import { useHistory } from 'react-router-dom'
import React, { useEffect, useState } from 'react'
import * as Yup from 'yup'
import { loginCompetition } from '../../../actions/competitionLogin'
import { useAppDispatch, useAppSelector } from '../../../hooks'
......@@ -37,8 +36,9 @@ const CompetitionLogin: React.FC = () => {
model: { code: '' },
}
const handleCompetitionSubmit = async (values: CompetitionLoginFormModel) => {
dispatch(loginCompetition(values.model.code, history))
dispatch(loginCompetition(values.model.code, history, true))
}
return (
<Formik
initialValues={competitionInitialValues}
......
import { Button, CircularProgress, Divider, Menu, MenuItem, Typography } from '@material-ui/core'
import { Button, CircularProgress, Divider, Menu, MenuItem } from '@material-ui/core'
import CssBaseline from '@material-ui/core/CssBaseline'
import ListItemText from '@material-ui/core/ListItemText'
import AddOutlinedIcon from '@material-ui/icons/AddOutlined'
......@@ -17,21 +17,21 @@ import SlideDisplay from './components/SlideDisplay'
import {
AppBarEditor,
CenteredSpinnerContainer,
CompetitionName,
FillLeftContainer,
FillRightContainer,
HomeIcon,
LeftDrawer,
RightDrawer,
PositionBottom,
PresentationEditorContainer,
RightDrawer,
RightPanelScroll,
SlideList,
SlideListItem,
ToolBarContainer,
ToolbarMargin,
ViewButton,
ViewButtonGroup,
ToolbarMargin,
FillLeftContainer,
PositionBottom,
FillRightContainer,
CompetitionName,
RightPanelScroll,
} from './styled'
const initialState = {
......@@ -113,7 +113,7 @@ const PresentationEditorPage: React.FC = () => {
return (
<PresentationEditorContainer>
<CssBaseline />
<AppBarEditor leftDrawerWidth={leftDrawerWidth} rightDrawerWidth={rightDrawerWidth} position="fixed">
<AppBarEditor $leftDrawerWidth={leftDrawerWidth} $rightDrawerWidth={rightDrawerWidth} position="fixed">
<ToolBarContainer>
<Button component={Link} to="/admin/tävlingshanterare" style={{ padding: 0 }}>
<HomeIcon src="/t8.png" />
......@@ -142,8 +142,8 @@ const PresentationEditorPage: React.FC = () => {
</ViewButtonGroup>
</ToolBarContainer>
</AppBarEditor>
<LeftDrawer leftDrawerWidth={leftDrawerWidth} rightDrawerWidth={undefined} variant="permanent" anchor="left">
<FillLeftContainer leftDrawerWidth={leftDrawerWidth} rightDrawerWidth={undefined}>
<LeftDrawer $leftDrawerWidth={leftDrawerWidth} $rightDrawerWidth={undefined} variant="permanent" anchor="left">
<FillLeftContainer $leftDrawerWidth={leftDrawerWidth} $rightDrawerWidth={undefined}>
<ToolbarMargin />
<SlideList>
{competition.slides &&
......@@ -166,13 +166,13 @@ const PresentationEditorPage: React.FC = () => {
<SlideListItem divider button onClick={() => createNewSlide()}>
<ListItemText primary="Ny sida" />
<AddOutlinedIcon />
</SlideListItem>
</SlideListItem>
</PositionBottom>
</FillLeftContainer>
</LeftDrawer>
<ToolbarMargin />
<RightDrawer leftDrawerWidth={undefined} rightDrawerWidth={rightDrawerWidth} variant="permanent" anchor="right">
<FillRightContainer leftDrawerWidth={undefined} rightDrawerWidth={rightDrawerWidth}>
<RightDrawer $leftDrawerWidth={undefined} $rightDrawerWidth={rightDrawerWidth} variant="permanent" anchor="right">
<FillRightContainer $leftDrawerWidth={undefined} $rightDrawerWidth={rightDrawerWidth}>
<RightPanelScroll>
{!competitionLoading ? (
<SettingsPanel />
......
import { Button, Card, IconButton, Tooltip, Typography } from '@material-ui/core'
import { Card, IconButton, Tooltip } from '@material-ui/core'
import axios from 'axios'
import React, { useEffect, useState } from 'react'
import { Rnd } from 'react-rnd'
import { ComponentTypes } from '../../../enum/ComponentTypes'
import { useAppSelector } from '../../../hooks'
import { Component, ImageComponent, QuestionAlternativeComponent, TextComponent } from '../../../interfaces/ApiModels'
import { Component, ImageComponent, TextComponent } from '../../../interfaces/ApiModels'
import { Position, Size } from '../../../interfaces/Components'
import CheckboxComponent from './CheckboxComponent'
import ImageComponentDisplay from './ImageComponentDisplay'
import { HoverContainer } from './styled'
import FormatAlignCenterIcon from '@material-ui/icons/FormatAlignCenter'
import TextComponentDisplay from './TextComponentDisplay'
type RndComponentProps = {
......@@ -42,13 +40,11 @@ const RndComponent = ({ component, width, height, scale }: RndComponentProps) =>
})
}
const handleCenterHorizontal = () => {
console.log(width, currentSize.w)
const centerX = width / (2 * scale) - currentSize.w / 2
setCurrentPos({ x: centerX, y: currentPos.y })
handleUpdatePos({ x: centerX, y: currentPos.y })
}
const handleCenterVertical = () => {
console.log(height, currentSize.h)
const centerY = height / (2 * scale) - currentSize.h / 2
setCurrentPos({ x: currentPos.x, y: centerY })
handleUpdatePos({ x: currentPos.x, y: centerY })
......
......@@ -36,7 +36,6 @@ const TextComponentEdit = ({ component }: ImageComponentProps) => {
//Only updates 250ms after last input was made to not spam
setTimerHandle(
window.setTimeout(async () => {
console.log('Content was updated on server. id: ', component.id)
await axios.put(`/api/competitions/${competitionId}/slides/${activeSlideId}/components/${component.id}`, {
text: newText,
})
......
import { ListItem, ListItemText, TextField, withStyles } from '@material-ui/core'
import { ListItem, ListItemText, TextField } from '@material-ui/core'
import axios from 'axios'
import React from 'react'
import { getEditorCompetition } from '../../../../actions/editor'
......@@ -23,7 +23,6 @@ const Instructions = ({ activeSlide, competitionId }: InstructionsProps) => {
//Only updates 250ms after last input was made to not spam
setTimerHandle(
window.setTimeout(async () => {
console.log('Content was updated on server. id: ', activeSlide.questions[0].id)
if (activeSlide && activeSlide.questions[0]) {
await axios
// TODO: Implement instructions field in question and add put API
......
......@@ -18,7 +18,6 @@ const QuestionSettings = ({ activeSlide, competitionId }: QuestionSettingsProps)
updateTitle: boolean,
event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
) => {
console.log('Content was updated on server. id: ', activeSlide.questions[0].id)
if (activeSlide && activeSlide.questions[0]) {
if (updateTitle) {
await axios
......
......@@ -6,8 +6,8 @@ interface ViewButtonProps {
}
interface DrawerSizeProps {
leftDrawerWidth: number | undefined
rightDrawerWidth: number | undefined
$leftDrawerWidth: number | undefined
$rightDrawerWidth: number | undefined
}
const AppBarHeight = 64
......@@ -66,22 +66,22 @@ export const HomeIcon = styled.img`
`
export const LeftDrawer = styled(Drawer)<DrawerSizeProps>`
width: ${(props) => (props ? props.leftDrawerWidth : 0)}px;
width: ${(props) => (props ? props.$leftDrawerWidth : 0)}px;
flex-shrink: 0;
position: relative;
z-index: 1;
`
export const RightDrawer = styled(Drawer)<DrawerSizeProps>`
width: ${(props) => (props ? props.rightDrawerWidth : 0)}px;
width: ${(props) => (props ? props.$rightDrawerWidth : 0)}px;
flex-shrink: 0;
`
export const AppBarEditor = styled(AppBar)<DrawerSizeProps>`
width: calc(100% - ${(props) => (props ? props.rightDrawerWidth : 0)}px);
width: calc(100% - ${(props) => (props ? props.$rightDrawerWidth : 0)}px);
left: 0;
margin-left: leftDrawerWidth;
margin-right: rightDrawerWidth;
margin-left: $leftDrawerWidth;
margin-right: $rightDrawerWidth;
`
// Necessary for content to be below app bar
......@@ -90,13 +90,13 @@ export const ToolbarMargin = styled.div`
`
export const FillLeftContainer = styled.div<DrawerSizeProps>`
width: ${(props) => (props ? props.leftDrawerWidth : 0)}px;
width: ${(props) => (props ? props.$leftDrawerWidth : 0)}px;
height: calc(100% - ${SlideListHeight}px);
overflow: hidden;
`
export const FillRightContainer = styled.div<DrawerSizeProps>`
width: ${(props) => (props ? props.rightDrawerWidth : 0)}px;
width: ${(props) => (props ? props.$rightDrawerWidth : 0)}px;
height: 100%;
overflow-y: auto;
background: #e9e9e9;
......
import { render } from '@testing-library/react'
import mockedAxios from 'axios'
import React from 'react'
import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom'
import store from '../../store'
import AudienceViewPage from './AudienceViewPage'
it('renders audience view page', () => {
const typeRes: any = {
data: { id: 5, slides: [{ id: 2 }] },
}
;(mockedAxios.get as jest.Mock).mockImplementation(() => {
return Promise.resolve(typeRes)
})
render(
<Provider store={store}>
<AudienceViewPage />
</Provider>
<BrowserRouter>
<Provider store={store}>
<AudienceViewPage />
</Provider>
</BrowserRouter>
)
})
import { Typography } from '@material-ui/core'
import React from 'react'
import { useAppSelector } from '../../hooks'
import React, { useEffect } from 'react'
import { useParams } from 'react-router-dom'
import { getPresentationCompetition } from '../../actions/presentation'
import { useAppDispatch, useAppSelector } from '../../hooks'
import { ViewParams } from '../../interfaces/ViewParams'
import { socketConnect, socketJoinPresentation } from '../../sockets'
import SlideDisplay from '../presentationEditor/components/SlideDisplay'
import { PresentationBackground, PresentationContainer } from './styled'
const AudienceViewPage: React.FC = () => {
const { competitionId }: ViewParams = useParams()
const code = useAppSelector((state) => state.presentation.code)
const dispatch = useAppDispatch()
const viewTypes = useAppSelector((state) => state.types.viewTypes)
const activeViewTypeId = viewTypes.find((viewType) => viewType.name === 'Audience')?.id
useEffect(() => {
dispatch(getPresentationCompetition(competitionId))
if (code && code !== '') {
socketConnect()
socketJoinPresentation()
}
}, [])
if (activeViewTypeId) {
return <SlideDisplay variant="presentation" activeViewTypeId={activeViewTypeId} />
return (
<PresentationBackground>
<PresentationContainer>
<SlideDisplay variant="presentation" activeViewTypeId={activeViewTypeId} />
</PresentationContainer>
</PresentationBackground>
)
}
return <Typography>Error: Åskådarvyn kunde inte laddas</Typography>
}
......
import { Card, Divider, List, ListItem, ListItemText, Paper, Typography } from '@material-ui/core'
import { Divider, List, ListItemText, Typography } from '@material-ui/core'
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
import React, { useEffect, useState } from 'react'
import { getPresentationCompetition, setCurrentSlide, setPresentationCode } from '../../actions/presentation'
import { useHistory, useParams } from 'react-router-dom'
import { getPresentationCompetition, setCurrentSlide } from '../../actions/presentation'
import { useAppDispatch, useAppSelector } from '../../hooks'
import { ViewParams } from '../../interfaces/ViewParams'
import { socket_connect } from '../../sockets'
import { socketConnect } from '../../sockets'
import { renderSlideIcon } from '../../utils/renderSlideIcon'
import SlideDisplay from '../presentationEditor/components/SlideDisplay'
import { SlideListItem } from '../presentationEditor/styled'
import JudgeScoreDisplay from './components/JudgeScoreDisplay'
import PresentationComponent from './components/PresentationComponent'
import { useHistory } from 'react-router-dom'
import JudgeScoringInstructions from './components/JudgeScoringInstructions'
import {
Content,
InnerContent,
......@@ -18,13 +20,10 @@ import {
JudgeToolbar,
LeftDrawer,
RightDrawer,
ScoreFooterPadding,
ScoreHeaderPadding,
ScoreHeaderPaper,
ScoreFooterPadding,
} from './styled'
import SlideDisplay from '../presentationEditor/components/SlideDisplay'
import JudgeScoringInstructions from './components/JudgeScoringInstructions'
import { renderSlideIcon } from '../../utils/renderSlideIcon'
const leftDrawerWidth = 150
const rightDrawerWidth = 700
......@@ -40,32 +39,25 @@ const useStyles = makeStyles((theme: Theme) =>
toolbar: theme.mixins.toolbar,
})
)
type JudgeViewPageProps = {
//Prop to distinguish between editor and active competition
competitionId: number
code: string
}
const JudgeViewPage = ({ competitionId, code }: JudgeViewPageProps) => {
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 activeViewTypeId = viewTypes.find((viewType) => viewType.name === 'Judge')?.id
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 handleSelectSlide = (index: number) => {
setActiveSlideIndex(index)
dispatch(setCurrentSlide(slides[index]))
}
useEffect(() => {
socket_connect()
dispatch(getPresentationCompetition(competitionId.toString()))
dispatch(setPresentationCode(code))
//hides the url so people can't sneak peak
history.push('judge')
socketConnect()
dispatch(getPresentationCompetition(competitionId))
}, [])
return (
......
import { render } from '@testing-library/react'
import mockedAxios from 'axios'
import React from 'react'
import { act } from 'react-dom/test-utils'
import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom'
import store from '../../store'
import OperatorViewPage from './OperatorViewPage'
it('renders presenter view page', () => {
const compRes: any = {
data: {
slides: [{ id: 0, title: '' }],
},
}
const teamsRes: any = {
data: {
items: [
{
id: 1,
name: 'team1',
},
{
id: 2,
name: 'team2',
},
],
count: 2,
total_count: 3,
},
}
it('renders operator view page', async () => {
await act(async () => {
const compRes: any = {
data: {
slides: [{ id: 0, title: '' }],
},
}
const teamsRes: any = {
data: {
items: [
{
id: 1,
name: 'team1',
},
{
id: 2,
name: 'team2',
},
],
count: 2,
total_count: 3,
},
}
;(mockedAxios.get as jest.Mock).mockImplementation((path: string, params?: any) => {
if (path.endsWith('/teams')) return Promise.resolve(teamsRes)
else return Promise.resolve(compRes)
;(mockedAxios.get as jest.Mock).mockImplementation((path: string, params?: any) => {
if (path.endsWith('/teams')) return Promise.resolve(teamsRes)
else return Promise.resolve(compRes)
})
render(
<BrowserRouter>
<Provider store={store}>
<OperatorViewPage />
</Provider>
</BrowserRouter>
)
})
render(
<BrowserRouter>
<Provider store={store}>
<OperatorViewPage />
</Provider>
</BrowserRouter>
)
})
......@@ -15,45 +15,42 @@ import {
Theme,
Tooltip,
Typography,
useMediaQuery,
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'
import FileCopyIcon from '@material-ui/icons/FileCopy'
import SupervisorAccountIcon from '@material-ui/icons/SupervisorAccount'
import TimerIcon from '@material-ui/icons/Timer'
import React, { useEffect, useState } from 'react'
import axios from 'axios'
import React, { useEffect } from 'react'
import { useHistory, useParams } from 'react-router-dom'
import { getPresentationCompetition, setPresentationCode } from '../../actions/presentation'
import { getPresentationCompetition } from '../../actions/presentation'
import { useAppDispatch, useAppSelector } from '../../hooks'
import { Team } from '../../interfaces/ApiModels'
import { ViewParams } from '../../interfaces/ViewParams'
import {
socketConnect,
socketEndPresentation,
socketSetSlide,
socketSetSlideNext,
socketSetSlidePrev,
socketStartPresentation,
socketStartTimer,
socket_connect,
} from '../../sockets'
import SlideDisplay from '../presentationEditor/components/SlideDisplay'
import PresentationComponent from './components/PresentationComponent'
import Timer from './components/Timer'
import {
OperatorButton,
OperatorContainer,
OperatorContent,
OperatorFooter,
OperatorHeader,
OperatorContent,
OperatorInnerContent,
SlideCounter,
ToolBarContainer,
} from './styled'
import axios from 'axios'
import { Team } from '../../interfaces/ApiModels'
/**
* Description:
......@@ -111,18 +108,17 @@ const OperatorViewPage: React.FC = () => {
const classes = useStyles()
//const teams = useAppSelector((state) => state.presentation.competition.teams)
const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null)
const { id, code }: ViewParams = useParams()
const { competitionId }: ViewParams = useParams()
const presentation = useAppSelector((state) => state.presentation)
const activeId = useAppSelector((state) => state.presentation.competition.id)
const history = useHistory()
const dispatch = useAppDispatch()
const viewTypes = useAppSelector((state) => state.types.viewTypes)
const activeViewTypeId = viewTypes.find((viewType) => viewType.name === 'Operator')?.id
const activeViewTypeId = viewTypes.find((viewType) => viewType.name === 'Audience')?.id
useEffect(() => {
dispatch(getPresentationCompetition(id))
dispatch(setPresentationCode(code))
socket_connect()
dispatch(getPresentationCompetition(competitionId))
socketConnect()
socketSetSlide // Behövs denna?
handleOpenCodes()
setTimeout(startCompetition, 1000) // Ghetto, wait for everything to load
......@@ -148,7 +144,7 @@ const OperatorViewPage: React.FC = () => {
const startCompetition = () => {
socketStartPresentation()
console.log('started competition for')
console.log(id)
console.log(competitionId)
}
const handleVerifyExit = () => {
......@@ -177,7 +173,6 @@ const OperatorViewPage: React.FC = () => {
await axios
.get(`/api/competitions/${activeId}/codes`)
.then((response) => {
console.log(response.data)
setCodes(response.data.items)
})
.catch(console.log)
......@@ -187,7 +182,6 @@ const OperatorViewPage: React.FC = () => {
await axios
.get(`/api/competitions/${activeId}/teams`)
.then((response) => {
console.log(response.data.items)
setTeams(response.data.items)
})
.catch((err) => {
......@@ -199,7 +193,6 @@ const OperatorViewPage: React.FC = () => {
await axios
.get(`/api/competitions/${activeId}`)
.then((response) => {
console.log(response.data.name)
setCompetitionName(response.data.name)
})
.catch((err) => {
......@@ -249,28 +242,29 @@ const OperatorViewPage: React.FC = () => {
</DialogTitle>
<DialogContent>
{/* <DialogContentText>Här visas tävlingskoderna till den valda tävlingen.</DialogContentText> */}
{codes.map((code) => (
<ListItem key={code.id} style={{ display: 'flex' }}>
<ListItemText primary={`${getTypeName(code)}: `} />
<Typography component="div">
<ListItemText style={{ textAlign: 'right', marginLeft: '10px' }}>
<Box fontFamily="Monospace" fontWeight="fontWeightBold">
{code.code}
</Box>
</ListItemText>
</Typography>
<Tooltip title="Kopiera kod" arrow>
<Button
margin-right="0px"
onClick={() => {
navigator.clipboard.writeText(code.code)
}}
>
<FileCopyIcon fontSize="small" />
</Button>
</Tooltip>
</ListItem>
))}
{codes &&
codes.map((code) => (
<ListItem key={code.id} style={{ display: 'flex' }}>
<ListItemText primary={`${getTypeName(code)}: `} />
<Typography component="div">
<ListItemText style={{ textAlign: 'right', marginLeft: '10px' }}>
<Box fontFamily="Monospace" fontWeight="fontWeightBold">
{code.code}
</Box>
</ListItemText>
</Typography>
<Tooltip title="Kopiera kod" arrow>
<Button
margin-right="0px"
onClick={() => {
navigator.clipboard.writeText(code.code)
}}
>
<FileCopyIcon fontSize="small" />
</Button>
</Tooltip>
</ListItem>
))}
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
......
import { render } from '@testing-library/react'
import mockedAxios from 'axios'
import React from 'react'
import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom'
import store from '../../store'
import TeamViewPage from './TeamViewPage'
import mockedAxios from 'axios'
it('renders participant view page', () => {
const res = {
data: {},
data: { slides: [{ id: 5 }] },
}
;(mockedAxios.get as jest.Mock).mockImplementation(() => {
return Promise.resolve(res)
......
import React, { useEffect } from 'react'
import PresentationComponent from './components/PresentationComponent'
import { useHistory } from 'react-router-dom'
import { useHistory, useParams } from 'react-router-dom'
import { getPresentationCompetition } from '../../actions/presentation'
import { useAppDispatch, useAppSelector } from '../../hooks'
import { ViewParams } from '../../interfaces/ViewParams'
import { socketConnect, socketJoinPresentation } from '../../sockets'
import SlideDisplay from '../presentationEditor/components/SlideDisplay'
import { TeamContainer } from './styled'
import { socketJoinPresentation, socket_connect } from '../../sockets'
import { useAppSelector } from '../../hooks'
import { PresentationBackground, PresentationContainer } from './styled'
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 === 'Team')?.id
const { competitionId }: ViewParams = useParams()
const dispatch = useAppDispatch()
useEffect(() => {
//hides the url so people can't sneak peak
history.push('team')
dispatch(getPresentationCompetition(competitionId))
if (code && code !== '') {
socket_connect()
socketConnect()
socketJoinPresentation()
}
}, [])
return (
<TeamContainer>
{activeViewTypeId && <SlideDisplay variant="presentation" activeViewTypeId={activeViewTypeId} />}
</TeamContainer>
<PresentationBackground>
<PresentationContainer>
{activeViewTypeId && <SlideDisplay variant="presentation" activeViewTypeId={activeViewTypeId} />}
</PresentationContainer>
</PresentationBackground>
)
}
......
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