Skip to content
Snippets Groups Projects
Commit d488a39f authored by Björn Modée's avatar Björn Modée
Browse files

Resolve "Competition view"

parent 11c063fc
No related branches found
No related tags found
1 merge request!82Resolve "Competition view"
Pipeline #41671 passed with warnings
......@@ -10,10 +10,17 @@ import { City } from '../../../interfaces/ApiModels'
import { AddCompetitionModel, FormModel } from '../../../interfaces/FormModels'
import { AddButton, AddContent, AddForm } from '../styledComp'
/**
* Component description:
* This component handles the functionality when adding a competition to the system
* This component is a child component to CompetitionManager.tsx
*/
type formType = FormModel<AddCompetitionModel>
const noCitySelected = 'Välj stad'
//Description of the form and what is required
const competitionSchema: Yup.SchemaOf<formType> = Yup.object({
model: Yup.object()
.shape({
......@@ -45,20 +52,25 @@ const AddCompetition: React.FC = (props: any) => {
const dispatch = useAppDispatch()
const id = open ? 'simple-popover' : undefined
const currentYear = new Date().getFullYear()
// Handles the actual submition to the database
const handleCompetitionSubmit = async (values: formType, actions: FormikHelpers<formType>) => {
// The parameters sent
const params = {
name: values.model.name,
year: values.model.year,
city_id: selectedCity?.id as number,
}
await axios
.post('/competitions', params)
.post('/competitions', params) // send to database
.then(() => {
actions.resetForm()
actions.resetForm() // reset the form
setAnchorEl(null)
dispatch(getCompetitions())
dispatch(getCompetitions()) // refresh competitions
setSelectedCity(undefined)
})
// if the post request fails
.catch(({ response }) => {
console.warn(response.data)
if (response.data && response.data.message)
......@@ -83,6 +95,12 @@ const AddCompetition: React.FC = (props: any) => {
>
Ny Tävling
</AddButton>
{/**
* The "pop up" menu for adding a competition
* contains 3 fields; Name, Region and Year
*
*/}
<Popover
id={id}
open={open}
......
......@@ -21,6 +21,13 @@ import { CompetitionFilterParams } from '../../../interfaces/FilterParams'
import { FilterContainer, RemoveMenuItem, TopBar, YearFilterTextField } from '../styledComp'
import AddCompetition from './AddCompetition'
/**
* Component description:
* This component shows a list of all the competitions which a user can search through
* We can also start, duplicate or delete a competition
*/
// Use defined styling
const useStyles = makeStyles((theme: Theme) =>
createStyles({
table: {
......@@ -41,6 +48,7 @@ const CompetitionManager: React.FC = (props: any) => {
const filterParams = useAppSelector((state) => state.competitions.filterParams)
const competitionTotal = useAppSelector((state) => state.competitions.total)
const cities = useAppSelector((state) => state.cities.cities)
const classes = useStyles()
const noFilterText = 'Alla'
const dispatch = useAppDispatch()
......@@ -59,6 +67,7 @@ const CompetitionManager: React.FC = (props: any) => {
dispatch(getCompetitions())
}, [])
// Search funtion to search for a specific string
const onSearchChange = (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
if (timerHandle) {
clearTimeout(timerHandle)
......@@ -69,13 +78,14 @@ const CompetitionManager: React.FC = (props: any) => {
dispatch(setFilterParams({ ...filterParams, name: event.target.value }))
}
// Function to remove a competition from the systems database
const handleDeleteCompetition = async () => {
if (activeId) {
await axios
.delete(`/competitions/${activeId}`)
.then(() => {
setAnchorEl(null)
dispatch(getCompetitions())
dispatch(getCompetitions()) // refresh the competition list
})
.catch(({ response }) => {
console.warn(response.data)
......@@ -177,6 +187,7 @@ const CompetitionManager: React.FC = (props: any) => {
))}
</TableBody>
</Table>
{/** We can't find any competitions at all or with a specific filter */}
{(!competitions || competitions.length === 0) && (
<Typography>Inga tävlingar hittades med nuvarande filter</Typography>
)}
......
import React from 'react'
import SlideDisplay from './components/SlideDisplay'
const AudienceViewPage: React.FC = () => {
return <div>Publik</div>
return <SlideDisplay />
}
export default AudienceViewPage
import { Divider, List, ListItemText } 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 { useParams } from 'react-router-dom'
......@@ -10,6 +10,7 @@ import {
} from '../../actions/presentation'
import { useAppDispatch, useAppSelector } from '../../hooks'
import { ViewParams } from '../../interfaces/ViewParams'
import { socket_connect } from '../../sockets'
import { SlideListItem } from '../presentationEditor/styled'
import JudgeScoreDisplay from './components/JudgeScoreDisplay'
import SlideDisplay from './components/SlideDisplay'
......@@ -43,17 +44,20 @@ const JudgeViewPage: React.FC = () => {
const { id, code }: ViewParams = useParams()
const dispatch = useAppDispatch()
const [activeSlideIndex, setActiveSlideIndex] = useState<number>(0)
useEffect(() => {
dispatch(getPresentationCompetition(id))
dispatch(getPresentationTeams(id))
dispatch(setPresentationCode(code))
}, [])
const teams = useAppSelector((state) => state.presentation.teams)
const slides = useAppSelector((state) => state.presentation.competition.slides)
const handleSelectSlide = (index: number) => {
setActiveSlideIndex(index)
dispatch(setCurrentSlide(slides[index]))
}
useEffect(() => {
socket_connect()
dispatch(getPresentationCompetition(id))
dispatch(getPresentationTeams(id))
dispatch(setPresentationCode(code))
}, [])
return (
<div>
<JudgeAppBar position="fixed">
......@@ -80,6 +84,7 @@ const JudgeViewPage: React.FC = () => {
button
key={slide.id}
>
<Typography variant="h6">Slide ID: {slide.id} </Typography>
<ListItemText primary={slide.title} />
</SlideListItem>
))}
......@@ -103,7 +108,6 @@ const JudgeViewPage: React.FC = () => {
))}
</List>
</RightDrawer>
aaa
<Content leftDrawerWidth={leftDrawerWidth} rightDrawerWidth={rightDrawerWidth}>
<div className={classes.toolbar} />
<SlideDisplay />
......
import { List, ListItem, Popover } from '@material-ui/core'
import { List, ListItem, Popover, Tooltip, Typography } from '@material-ui/core'
import AssignmentIcon from '@material-ui/icons/Assignment'
import BackspaceIcon from '@material-ui/icons/Backspace'
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft'
import ChevronRightIcon from '@material-ui/icons/ChevronRight'
import PlayArrowIcon from '@material-ui/icons/PlayArrow'
import TimerIcon from '@material-ui/icons/Timer'
import React, { useEffect } from 'react'
import { useHistory, useParams } from 'react-router-dom'
import { getPresentationCompetition, getPresentationTeams, setPresentationCode } from '../../actions/presentation'
import { useAppDispatch, useAppSelector } from '../../hooks'
import { ViewParams } from '../../interfaces/ViewParams'
import {
socketEndPresentation,
socketSetSlide,
socketSetSlideNext,
socketSetSlidePrev,
socketStartPresentation,
socketStartTimer,
socket_connect,
} from '../../sockets'
import SlideDisplay from './components/SlideDisplay'
import SocketTest from './components/SocketTest'
import Timer from './components/Timer'
import { PresenterButton, PresenterContainer, PresenterFooter, PresenterHeader } from './styled'
import {
PresenterButton,
PresenterContainer,
PresenterFooter,
PresenterHeader,
SlideCounter,
ToolBarContainer,
} from './styled'
const PresenterViewPage: React.FC = () => {
const teams = useAppSelector((state) => state.presentation.teams)
const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null)
const { id, code }: ViewParams = useParams()
const presentation = useAppSelector((state) => state.presentation)
const history = useHistory()
const dispatch = useAppDispatch()
useEffect(() => {
socket_connect()
socketSetSlide
dispatch(getPresentationCompetition(id))
dispatch(getPresentationTeams(id))
dispatch(setPresentationCode(code))
}, [])
const handleOpenPopover = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget)
}
const handleClose = () => {
setAnchorEl(null)
}
const handleNextSlidePressed = () => {
// dispatch(setCurrentSlideNext())
// syncSlide()
const startCompetition = () => {
socketStartPresentation()
const haveStarted = true
console.log('You have started the competition! GLHF!')
console.log(haveStarted)
}
const handlePreviousSlidePressed = () => {
// dispatch(setCurrentSlidePrevious())
// syncSlide()
const endCompetition = () => {
if (confirm('Är du säker på att du vill avsluta tävlingen för alla?')) {
const haveStarted = false
socketEndPresentation()
history.push('/admin')
window.location.reload(false) // TODO: fix this ugly hack, we "need" to refresh site to be able to run the competition correctly again
}
}
return (
<PresenterContainer>
<PresenterHeader>
<PresenterButton onClick={handleOpenPopover} color="primary" variant="contained">
Visa ställning
</PresenterButton>
<PresenterButton onClick={() => history.push('/admin')} variant="contained" color="secondary">
Avsluta tävling
</PresenterButton>
<Tooltip title="Avsluta tävling" arrow>
<PresenterButton onClick={endCompetition} variant="contained" color="secondary">
<BackspaceIcon fontSize="large" />
</PresenterButton>
</Tooltip>
<SlideCounter>
<Typography variant="h3">
{presentation.slide.id} / {presentation.competition.slides.length}
</Typography>
</SlideCounter>
</PresenterHeader>
<SlideDisplay />
<PresenterFooter>
<PresenterButton onClick={handlePreviousSlidePressed} variant="contained">
<ChevronRightIcon fontSize="large" />
</PresenterButton>
<SocketTest></SocketTest>
<Timer></Timer>
<PresenterButton onClick={handleNextSlidePressed} variant="contained">
<ChevronRightIcon fontSize="large" />
</PresenterButton>
<ToolBarContainer>
<Tooltip title="Previous Slide" arrow>
<PresenterButton onClick={socketSetSlidePrev} variant="contained">
<ChevronLeftIcon fontSize="large" />
</PresenterButton>
</Tooltip>
<Tooltip title="Start Presentation" arrow>
<PresenterButton onClick={startCompetition} variant="contained">
<PlayArrowIcon fontSize="large" />
</PresenterButton>
</Tooltip>
{/*
// This creates a join button, but presenter should not join others, others should join presenter
<Tooltip title="Join Presentation" arrow>
<PresenterButton onClick={socketJoinPresentation} variant="contained">
<GroupAddIcon fontSize="large" />
</PresenterButton>
</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">
<CancelIcon fontSize="large" />
</PresenterButton>
</Tooltip>
*/}
<Tooltip title="Start Timer" arrow>
<PresenterButton onClick={socketStartTimer} variant="contained">
<TimerIcon fontSize="large" />
<Timer></Timer>
</PresenterButton>
</Tooltip>
<Tooltip title="Scoreboard" arrow>
<PresenterButton onClick={handleOpenPopover} variant="contained">
<AssignmentIcon fontSize="large" />
</PresenterButton>
</Tooltip>
<Tooltip title="Next Slide" arrow>
<PresenterButton onClick={socketSetSlideNext} variant="contained">
<ChevronRightIcon fontSize="large" />
</PresenterButton>
</Tooltip>
</ToolBarContainer>
</PresenterFooter>
<Popover
open={Boolean(anchorEl)}
......@@ -71,6 +149,9 @@ const PresenterViewPage: React.FC = () => {
}}
>
<List>
{/** TODO:
* Fix scoreboard
*/}
{teams.map((team) => (
<ListItem key={team.id}>{team.name} score: 20</ListItem>
))}
......
import { Typography } from '@material-ui/core'
import React from 'react'
import { useAppSelector } from '../../../hooks'
import React, { useEffect } from 'react'
import { useAppDispatch, useAppSelector } from '../../../hooks'
import { SlideContainer } from './styled'
const SlideDisplay: React.FC = () => {
const currentSlide = useAppSelector((state) => state.presentation.slide)
const dispatch = useAppDispatch()
useEffect(() => {}, [])
return (
<SlideContainer>
<Typography variant="h3">{currentSlide.title}</Typography>
</SlideContainer>
<div>
<SlideContainer>
<Typography variant="h3">Slide Title: {currentSlide.title} </Typography>
<Typography variant="h3">Timer: {currentSlide.timer} </Typography>
<Typography variant="h3">Slide ID: {currentSlide.id} </Typography>
</SlideContainer>
</div>
)
}
......
......@@ -38,8 +38,7 @@ const Timer: React.FC = (props: any) => {
return (
<>
<div>Timer: {props.timer.value}</div>
<div>Enabled: {props.timer.enabled.toString()}</div>
<div>{props.timer.value}</div>
</>
)
}
......
......@@ -3,7 +3,14 @@ import styled from 'styled-components'
export const SlideContainer = styled.div`
display: flex;
flex-direction: column;
margin-left: auto;
margin-right: auto;
margin-top: 5%;
justify-content: center;
background-color: grey;
width: 1280px;
height: 720px;
`
export const ScoreDisplayContainer = styled.div`
......
......@@ -50,8 +50,15 @@ export const PresenterFooter = styled.div`
export const PresenterButton = styled(Button)`
width: 100px;
height: 100px;
padding-top: 16px;
padding-bottom: 16px;
margin-left: 16px;
margin-right: 16px;
margin-top: 16px;
`
export const SlideCounter = styled(Button)`
margin-left: 16px;
margin-right: 16px;
margin-top: 16px;
`
export const PresenterContainer = styled.div`
......@@ -61,6 +68,18 @@ export const PresenterContainer = styled.div`
height: 100%;
`
export const ToolBarContainer = styled.div`
align-self: center;
display: flex;
flex-direction: row;
justify-content: space-between;
height: 100%;
width: auto;
margin-right: auto;
margin-left: auto;
margin-bottom: 20px;
`
interface DrawerProps {
width: number
}
......
......@@ -38,22 +38,27 @@ export const socket_connect = () => {
export const socketStartPresentation = () => {
socket.emit('start_presentation', { competition_id: store.getState().presentation.competition.id })
console.log('START PRESENTATION')
}
export const socketJoinPresentation = () => {
socket.emit('join_presentation', { code: 'OEM1V4' }) // TODO: Send code gotten from auth/login/<code> api call
socket.emit('join_presentation', { code: 'CO0ART' }) // TODO: Send code gotten from auth/login/<code> api call
console.log('JOIN PRESENTATION')
}
export const socketEndPresentation = () => {
socket.emit('end_presentation', { competition_id: store.getState().presentation.competition.id })
console.log('END PRESENTATION')
}
export const socketSetSlideNext = () => {
socketSetSlide(store.getState().presentation.slide.order + 1) // TODO: Check that this slide exists
console.log('NEXT SLIDE +1')
}
export const socketSetSlidePrev = () => {
socketSetSlide(store.getState().presentation.slide.order - 1) // TODO: Check that this slide exists
console.log('PREVIOUS SLIDE -1')
}
export const socketSetSlide = (slide_order: number) => {
......@@ -69,6 +74,7 @@ export const socketSetSlide = (slide_order: number) => {
}
export const socketSetTimer = (timer: Timer) => {
console.log('SET TIMER')
socket.emit('set_timer', {
competition_id: store.getState().presentation.competition.id,
timer: timer,
......@@ -76,5 +82,6 @@ export const socketSetTimer = (timer: Timer) => {
}
export const socketStartTimer = () => {
console.log('START TIMER')
socketSetTimer({ enabled: true, value: store.getState().presentation.timer.value })
}
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