diff --git a/client/src/Main.tsx b/client/src/Main.tsx index b7c74b556e3e072f8da96d328617d7461977b4c9..b999a9775f21bbc999dd1bbd00ca773bdb1ea02c 100644 --- a/client/src/Main.tsx +++ b/client/src/Main.tsx @@ -22,7 +22,7 @@ const Main: React.FC = () => { <Switch> <SecureRoute login exact path="/" component={LoginPage} /> <SecureRoute path="/admin" component={AdminPage} /> - <SecureRoute path="/editor/competition-id=:id" component={PresentationEditorPage} /> + <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} /> diff --git a/client/src/pages/presentationEditor/PresentationEditorPage.tsx b/client/src/pages/presentationEditor/PresentationEditorPage.tsx index 5ce395e260b5ff60021fa9039c59e24fc7aee05a..3c86afe9b76d2a618bd6396ff6c4e7edd782d8e7 100644 --- a/client/src/pages/presentationEditor/PresentationEditorPage.tsx +++ b/client/src/pages/presentationEditor/PresentationEditorPage.tsx @@ -83,18 +83,18 @@ const useStyles = makeStyles((theme: Theme) => ) interface CompetitionParams { - id: string + competitionId: string } const PresentationEditorPage: React.FC = () => { const classes = useStyles() - const { id }: CompetitionParams = useParams() + const { competitionId }: CompetitionParams = useParams() const dispatch = useAppDispatch() const activeSlideId = useAppSelector((state) => state.editor.activeSlideId) const competition = useAppSelector((state) => state.editor.competition) const competitionLoading = useAppSelector((state) => state.editor.loading) useEffect(() => { - dispatch(getEditorCompetition(id)) + dispatch(getEditorCompetition(competitionId)) dispatch(getCities()) dispatch(getTypes()) }, []) @@ -104,8 +104,8 @@ const PresentationEditorPage: React.FC = () => { } const createNewSlide = async () => { - await axios.post(`/api/competitions/${id}/slides`, { title: 'new slide' }) - dispatch(getEditorCompetition(id)) + await axios.post(`/api/competitions/${competitionId}/slides`, { title: 'new slide' }) + dispatch(getEditorCompetition(competitionId)) } const [contextState, setContextState] = React.useState<{ @@ -128,14 +128,14 @@ const PresentationEditorPage: React.FC = () => { } const handleRemoveSlide = async () => { - await axios.delete(`/api/competitions/${id}/slides/${contextState.slideId}`) - dispatch(getEditorCompetition(id)) + await axios.delete(`/api/competitions/${competitionId}/slides/${contextState.slideId}`) + dispatch(getEditorCompetition(competitionId)) setContextState(initialState) } const handleDuplicateSlide = async () => { - await axios.post(`/api/competitions/${id}/slides/${contextState.slideId}/copy`) - dispatch(getEditorCompetition(id)) + await axios.post(`/api/competitions/${competitionId}/slides/${contextState.slideId}/copy`) + dispatch(getEditorCompetition(competitionId)) setContextState(initialState) } @@ -188,9 +188,6 @@ const PresentationEditorPage: React.FC = () => { <ViewButton variant="contained" color="secondary"> Deltagarvy </ViewButton> - <ViewButton variant="contained" color="secondary"> - Domarvy - </ViewButton> </ViewButtonGroup> </ToolBarContainer> </AppBar> diff --git a/client/src/pages/presentationEditor/components/CompetitionSettings.tsx b/client/src/pages/presentationEditor/components/CompetitionSettings.tsx index 53c2ecdb4dd23cc81df0140bd2bede66dfe18b88..7ea2a84f99171fd75555e606abe2681a7f3c0c0d 100644 --- a/client/src/pages/presentationEditor/components/CompetitionSettings.tsx +++ b/client/src/pages/presentationEditor/components/CompetitionSettings.tsx @@ -1,14 +1,7 @@ import { - Button, - Dialog, - DialogActions, - DialogContent, - DialogContentText, - DialogTitle, Divider, FormControl, InputLabel, - List, ListItem, ListItemText, MenuItem, @@ -16,84 +9,44 @@ import { TextField, Typography, } from '@material-ui/core' -import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' -import CloseIcon from '@material-ui/icons/Close' +import { Center, ImportedImage, SettingsList, PanelContainer, FirstItem, AddButton } from './styled' import axios from 'axios' import React, { useState } from 'react' import { useParams } from 'react-router-dom' import { getEditorCompetition } from '../../../actions/editor' import { useAppDispatch, useAppSelector } from '../../../hooks' import { City } from '../../../interfaces/ApiModels' - -const useStyles = makeStyles((theme: Theme) => - createStyles({ - textInputContainer: { - '& > *': { - margin: theme.spacing(1), - width: '100%', - background: 'white', - }, - }, - textInput: { - margin: theme.spacing(2), - width: '87%', - background: 'white', - }, - textCenter: { - textAlign: 'center', - }, - center: { - display: 'flex', - justifyContent: 'center', - background: 'white', - }, - importedImage: { - width: 70, - height: 50, - background: 'white', - }, - dropDown: { - margin: theme.spacing(2), - width: '87%', - background: 'white', - }, - addButtons: { - padding: 5, - }, - panelList: { - padding: 0, - }, - }) -) +import Teams from './Teams' interface CompetitionParams { - id: string + competitionId: string } const CompetitionSettings: React.FC = () => { - const classes = useStyles() - const { id }: CompetitionParams = useParams() + const { competitionId }: CompetitionParams = useParams() const dispatch = useAppDispatch() const competition = useAppSelector((state) => state.editor.competition) + const cities = useAppSelector((state) => state.cities.cities) + const updateCompetitionName = async (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => { await axios - .put(`/api/competitions/${id}`, { name: event.target.value }) + .put(`/api/competitions/${competitionId}`, { name: event.target.value }) .then(() => { - dispatch(getEditorCompetition(id)) + dispatch(getEditorCompetition(competitionId)) }) .catch(console.log) } - const cities = useAppSelector((state) => state.cities.cities) const updateCompetitionCity = async (city: City) => { await axios - .put(`/api/competitions/${id}`, { city_id: city.id }) + .put(`/api/competitions/${competitionId}`, { city_id: city.id }) .then(() => { - dispatch(getEditorCompetition(id)) + dispatch(getEditorCompetition(competitionId)) }) .catch(console.log) } + /* Finds the right city object from a city name */ const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => { cities.forEach((city) => { if (event.target.value === city.name) { @@ -102,109 +55,55 @@ const CompetitionSettings: React.FC = () => { }) } - const removeTeam = async (tid: number) => { - await axios - .delete(`/api/competitions/${id}/teams/${tid}`) - .then(() => { - dispatch(getEditorCompetition(id)) - }) - .catch(console.log) - } - const addTeam = async () => { - setAddTeamOpen(false) - await axios - .post(`/api/competitions/${id}/teams`, { name: selectedTeamName }) - .then(() => { - dispatch(getEditorCompetition(id)) - }) - .catch(console.log) - } - // For "add team" dialog - const [addTeamOpen, setAddTeamOpen] = useState(false) - const openAddTeam = () => { - setAddTeamOpen(true) - } - const closeAddTeam = () => { - setAddTeamOpen(false) - } - let selectedTeamName = '' - const updateSelectedTeamName = (event: React.ChangeEvent<{ value: string }>) => { - selectedTeamName = event.target.value - } - return ( - <div className={classes.textInputContainer}> - <form noValidate autoComplete="off"> - <TextField - className={classes.textInput} - id="outlined-basic" - label={'Tävlingsnamn'} - defaultValue={competition.name} - onChange={updateCompetitionName} - variant="outlined" - /> + <PanelContainer> + <SettingsList> + <FirstItem> + <ListItem> + <TextField + id="outlined-basic" + label={'Tävlingsnamn'} + defaultValue={competition.name} + onChange={updateCompetitionName} + variant="outlined" + fullWidth={true} + /> + </ListItem> + </FirstItem> <Divider /> - <FormControl variant="outlined" className={classes.dropDown}> - <InputLabel>Region</InputLabel> - <Select - value={cities.find((city) => city.id === competition.city_id)?.name || ''} - label="Region" - onChange={handleChange} - > - {cities.map((city) => ( - <MenuItem value={city.name} key={city.name}> - <Button>{city.name}</Button> - </MenuItem> - ))} - </Select> - </FormControl> - </form> - <List className={classes.panelList}> <ListItem> - <ListItemText className={classes.textCenter} primary="Lag" /> + <FormControl fullWidth variant="outlined"> + <InputLabel>Region</InputLabel> + <Select + value={cities.find((city) => city.id === competition.city_id)?.name || ''} + label="Region" + onChange={handleChange} + > + {cities.map((city) => ( + <MenuItem value={city.name} key={city.name}> + <Typography variant="button">{city.name}</Typography> + </MenuItem> + ))} + </Select> + </FormControl> </ListItem> - {competition.teams && - competition.teams.map((team) => ( - <div key={team.id}> - <ListItem divider button> - <ListItemText primary={team.name} /> - <CloseIcon onClick={() => removeTeam(team.id)} /> - </ListItem> - </div> - ))} + </SettingsList> - <ListItem className={classes.center} button onClick={openAddTeam}> - <Typography className={classes.addButtons} variant="button"> - Lägg till lag - </Typography> - </ListItem> - <Dialog open={addTeamOpen} onClose={closeAddTeam}> - <DialogTitle className={classes.center}>Lägg till lag</DialogTitle> - <DialogContent> - <DialogContentText>Skriv 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"> - Avbryt - </Button> - <Button onClick={addTeam} color="primary"> - Bekräfta - </Button> - </DialogActions> - </Dialog> - </List> + <Teams competitionId={competitionId} /> - <ListItem button> - <img - id="temp source, todo: add image source to elements of pictureList" - src="https://i1.wp.com/stickoutmedia.se/wp-content/uploads/2021/01/placeholder-3.png?ssl=1" - className={classes.importedImage} - /> - <ListItemText className={classes.textCenter}>Välj bakgrundsbild ...</ListItemText> - </ListItem> - </div> + <SettingsList> + <ListItem button> + <ImportedImage + id="temp source, todo: add image source to elements of pictureList" + src="https://i1.wp.com/stickoutmedia.se/wp-content/uploads/2021/01/placeholder-3.png?ssl=1" + /> + <Center> + <ListItemText>Välj bakgrundsbild ...</ListItemText> + </Center> + </ListItem> + </SettingsList> + </PanelContainer> ) } diff --git a/client/src/pages/presentationEditor/components/SlideSettings.tsx b/client/src/pages/presentationEditor/components/SlideSettings.tsx index 2f403f41ddf4ff66ad11301c213522c24bc81334..278887c1cb8b841224704ceb1f2e1bb9fa5c7b6a 100644 --- a/client/src/pages/presentationEditor/components/SlideSettings.tsx +++ b/client/src/pages/presentationEditor/components/SlideSettings.tsx @@ -7,18 +7,18 @@ import { useAppSelector } from '../../../hooks' import Instructions from './slideSettingsComponents/Instructions' import MultipleChoiceAlternatives from './slideSettingsComponents/MultipleChoiceAlternatives' import SlideType from './slideSettingsComponents/SlideType' -import { Center, ImportedImage, SettingsList, SlidePanel } from './styled' +import { Center, ImportedImage, SettingsList, PanelContainer } from './styled' import Timer from './slideSettingsComponents/Timer' import Images from './slideSettingsComponents/Images' import Texts from './slideSettingsComponents/Texts' import QuestionSettings from './slideSettingsComponents/QuestionSettings' interface CompetitionParams { - id: string + competitionId: string } const SlideSettings: React.FC = () => { - const { id }: CompetitionParams = useParams() + const { competitionId }: CompetitionParams = useParams() const activeSlide = useAppSelector((state) => // Gets the slide with id=activeSlideId from the database. @@ -26,26 +26,30 @@ const SlideSettings: React.FC = () => { ) return ( - <SlidePanel> + <PanelContainer> <SettingsList> - {activeSlide && <SlideType activeSlide={activeSlide} competitionId={id} />} + {activeSlide && <SlideType activeSlide={activeSlide} competitionId={competitionId} />} <Divider /> - {activeSlide && <Timer activeSlide={activeSlide} competitionId={id} />} + {activeSlide && <Timer activeSlide={activeSlide} competitionId={competitionId} />} </SettingsList> - {activeSlide?.questions[0] && <QuestionSettings activeSlide={activeSlide} competitionId={id} />} + {activeSlide?.questions[0] && <QuestionSettings activeSlide={activeSlide} competitionId={competitionId} />} { // Choose answer alternatives depending on the slide type } - {activeSlide?.questions[0]?.type_id === 1 && <Instructions activeSlide={activeSlide} competitionId={id} />} - {activeSlide?.questions[0]?.type_id === 2 && <Instructions activeSlide={activeSlide} competitionId={id} />} + {activeSlide?.questions[0]?.type_id === 1 && ( + <Instructions activeSlide={activeSlide} competitionId={competitionId} /> + )} + {activeSlide?.questions[0]?.type_id === 2 && ( + <Instructions activeSlide={activeSlide} competitionId={competitionId} /> + )} {activeSlide?.questions[0]?.type_id === 3 && ( - <MultipleChoiceAlternatives activeSlide={activeSlide} competitionId={id} /> + <MultipleChoiceAlternatives activeSlide={activeSlide} competitionId={competitionId} /> )} - {activeSlide && <Texts activeSlide={activeSlide} competitionId={id} />} + {activeSlide && <Texts activeSlide={activeSlide} competitionId={competitionId} />} - {activeSlide && <Images activeSlide={activeSlide} competitionId={id} />} + {activeSlide && <Images activeSlide={activeSlide} competitionId={competitionId} />} <SettingsList> <ListItem button> @@ -58,7 +62,7 @@ const SlideSettings: React.FC = () => { </Center> </ListItem> </SettingsList> - </SlidePanel> + </PanelContainer> ) } diff --git a/client/src/pages/presentationEditor/components/Teams.tsx b/client/src/pages/presentationEditor/components/Teams.tsx new file mode 100644 index 0000000000000000000000000000000000000000..564dbc847638f1d16e6d09b7ae96019e02856a07 --- /dev/null +++ b/client/src/pages/presentationEditor/components/Teams.tsx @@ -0,0 +1,100 @@ +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, + ListItem, + ListItemText, + TextField, +} from '@material-ui/core' +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' + +type TeamsProps = { + competitionId: string +} + +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) + } + // For "add team" dialog + const [addTeamOpen, setAddTeamOpen] = useState(false) + const openAddTeam = () => { + setAddTeamOpen(true) + } + const closeAddTeam = () => { + setAddTeamOpen(false) + } + let selectedTeamName = '' + const updateSelectedTeamName = (event: React.ChangeEvent<{ value: string }>) => { + selectedTeamName = event.target.value + } + + const removeTeam = async (tid: number) => { + await axios + .delete(`/api/competitions/${competitionId}/teams/${tid}`) + .then(() => { + dispatch(getEditorCompetition(competitionId)) + }) + .catch(console.log) + } + + return ( + <SettingsList> + <ListItem divider> + <Center> + <ListItemText primary="Lag" /> + </Center> + </ListItem> + {competition.teams && + competition.teams.map((team) => ( + <div key={team.id}> + <ListItem divider> + <ListItemText primary={team.name} /> + <Clickable> + <CloseIcon onClick={() => removeTeam(team.id)} /> + </Clickable> + </ListItem> + </div> + ))} + <ListItem button onClick={openAddTeam}> + <Center> + <AddButton variant="button">Lägg till lag</AddButton> + </Center> + </ListItem> + <Dialog open={addTeamOpen} onClose={closeAddTeam}> + <DialogTitle>Lägg till lag</DialogTitle> + <DialogContent> + <DialogContentText>Skriv 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"> + Avbryt + </Button> + <Button onClick={addTeam} color="primary"> + Bekräfta + </Button> + </DialogActions> + </Dialog> + </SettingsList> + ) +} + +export default Teams diff --git a/client/src/pages/presentationEditor/components/TextComponentEdit.tsx b/client/src/pages/presentationEditor/components/TextComponentEdit.tsx index 8ef64b2724aba0fa6a669250dbe185e0c7dffcee..b03696f37987a83347f57fb81c6b25febcb84824 100644 --- a/client/src/pages/presentationEditor/components/TextComponentEdit.tsx +++ b/client/src/pages/presentationEditor/components/TextComponentEdit.tsx @@ -12,12 +12,11 @@ type ImageComponentProps = { } interface CompetitionParams { - id: string + competitionId: string } const TextComponentEdit = ({ component }: ImageComponentProps) => { - const { id }: CompetitionParams = useParams() - const competitionId = useAppSelector((state) => state.editor.competition.id) + const { competitionId }: CompetitionParams = useParams() const [content, setContent] = useState('') const [timerHandle, setTimerHandle] = React.useState<number | undefined>(undefined) const activeSlideId = useAppSelector((state) => state.editor.activeSlideId) @@ -40,14 +39,14 @@ const TextComponentEdit = ({ component }: ImageComponentProps) => { await axios.put(`/api/competitions/${competitionId}/slides/${activeSlideId}/components/${component.id}`, { text: newText, }) - dispatch(getEditorCompetition(id)) + dispatch(getEditorCompetition(competitionId)) }, 250) ) } const handleDeleteText = async (componentId: number) => { - await axios.delete(`/api/competitions/${id}/slides/${activeSlideId}/components/${componentId}`) - dispatch(getEditorCompetition(id)) + await axios.delete(`/api/competitions/${competitionId}/slides/${activeSlideId}/components/${componentId}`) + dispatch(getEditorCompetition(competitionId)) } return ( diff --git a/client/src/pages/presentationEditor/components/slideSettingsComponents/Images.tsx b/client/src/pages/presentationEditor/components/slideSettingsComponents/Images.tsx index d8cc164cc8de656a7f732a92d35f9eb45572d453..fa087dccbb39c77a0a2e433d5a6a6c8b4d201fd1 100644 --- a/client/src/pages/presentationEditor/components/slideSettingsComponents/Images.tsx +++ b/client/src/pages/presentationEditor/components/slideSettingsComponents/Images.tsx @@ -2,14 +2,13 @@ */ import { ListItem, ListItemText, Typography } from '@material-ui/core' import CloseIcon from '@material-ui/icons/Close' -import React, { useState } from 'react' -import { useDispatch } from 'react-redux' +import React from 'react' import { Center, HiddenInput, SettingsList, AddImageButton, ImportedImage, AddButton } from '../styled' import axios from 'axios' import { getEditorCompetition } from '../../../../actions/editor' import { RichSlide } from '../../../../interfaces/ApiRichModels' import { ImageComponent, Media } from '../../../../interfaces/ApiModels' -import { useAppSelector } from '../../../../hooks' +import { useAppDispatch, useAppSelector } from '../../../../hooks' type ImagesProps = { activeSlide: RichSlide @@ -17,7 +16,7 @@ type ImagesProps = { } const Images = ({ activeSlide, competitionId }: ImagesProps) => { - const dispatch = useDispatch() + const dispatch = useAppDispatch() const uploadFile = async (formData: FormData) => { // Uploads the file to the server and creates a Media object in database. @@ -107,7 +106,7 @@ const Images = ({ activeSlide, competitionId }: ImagesProps) => { </div> ))} - <ListItem button> + <ListItem button style={{ padding: 0 }}> <HiddenInput accept="image/*" id="contained-button-file" multiple type="file" onChange={handleFileSelected} /> <AddImageButton htmlFor="contained-button-file"> <AddButton variant="button">Lägg till bild</AddButton> diff --git a/client/src/pages/presentationEditor/components/slideSettingsComponents/Instructions.tsx b/client/src/pages/presentationEditor/components/slideSettingsComponents/Instructions.tsx index 97b27c9d4fee4a39eaf0f4de28296621c35f8990..858dd75e65dc554cc6e1c2083f46873a925335a1 100644 --- a/client/src/pages/presentationEditor/components/slideSettingsComponents/Instructions.tsx +++ b/client/src/pages/presentationEditor/components/slideSettingsComponents/Instructions.tsx @@ -1,9 +1,8 @@ import { ListItem, ListItemText, TextField, withStyles } from '@material-ui/core' import axios from 'axios' import React from 'react' -import { useDispatch } from 'react-redux' import { getEditorCompetition } from '../../../../actions/editor' -import { useAppDispatch, useAppSelector } from '../../../../hooks' +import { useAppDispatch } from '../../../../hooks' import { RichSlide } from '../../../../interfaces/ApiRichModels' import { Center, SettingsList } from '../styled' @@ -13,12 +12,10 @@ type InstructionsProps = { } const Instructions = ({ activeSlide, competitionId }: InstructionsProps) => { - const dispatch = useDispatch() + const dispatch = useAppDispatch() const [timerHandle, setTimerHandle] = React.useState<number | undefined>(undefined) - const activeSlideId = useAppSelector((state) => state.editor.activeSlideId) const updateInstructionsText = async (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => { - /* TODO: Implement instructions field in question and add put API if (timerHandle) { clearTimeout(timerHandle) setTimerHandle(undefined) @@ -29,10 +26,11 @@ const Instructions = ({ activeSlide, competitionId }: InstructionsProps) => { 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 .put( `/api/competitions/${competitionId}/slides/${activeSlide.id}/questions/${activeSlide.questions[0].id}`, { - name: event.target.value, + instructions: event.target.value, } ) .then(() => { @@ -42,7 +40,6 @@ const Instructions = ({ activeSlide, competitionId }: InstructionsProps) => { } }, 250) ) - */ } return ( diff --git a/client/src/pages/presentationEditor/components/slideSettingsComponents/QuestionSettings.tsx b/client/src/pages/presentationEditor/components/slideSettingsComponents/QuestionSettings.tsx index 62afda68577c5153d7e253a7b8989dfcb3e6b28a..2bc10b3588133245d54767dbbc7d8381e4134b59 100644 --- a/client/src/pages/presentationEditor/components/slideSettingsComponents/QuestionSettings.tsx +++ b/client/src/pages/presentationEditor/components/slideSettingsComponents/QuestionSettings.tsx @@ -1,7 +1,6 @@ import { ListItem, ListItemText, TextField } from '@material-ui/core' import axios from 'axios' import React, { useEffect, useState } from 'react' -import { useDispatch } from 'react-redux' import { getEditorCompetition } from '../../../../actions/editor' import { useAppDispatch } from '../../../../hooks' import { RichSlide } from '../../../../interfaces/ApiRichModels' @@ -13,7 +12,7 @@ type QuestionSettingsProps = { } const QuestionSettings = ({ activeSlide, competitionId }: QuestionSettingsProps) => { - const dispatch = useDispatch() + const dispatch = useAppDispatch() const updateQuestion = async ( updateTitle: boolean, @@ -57,16 +56,14 @@ const QuestionSettings = ({ activeSlide, competitionId }: QuestionSettingsProps) </Center> </ListItem> <ListItem divider> - <Center> - <TextField - id="outlined-basic" - defaultValue={''} - label="Frågans titel" - onChange={(event) => updateQuestion(true, event)} - variant="outlined" - fullWidth={true} - /> - </Center> + <TextField + id="outlined-basic" + defaultValue={''} + label="Frågans titel" + onChange={(event) => updateQuestion(true, event)} + variant="outlined" + fullWidth={true} + /> </ListItem> <ListItem> <Center> diff --git a/client/src/pages/presentationEditor/components/slideSettingsComponents/SlideType.tsx b/client/src/pages/presentationEditor/components/slideSettingsComponents/SlideType.tsx index 3194f7c923db059113f9b7d2ad3c109387780029..bc251b91e092c05457db1b64bb8bbe566d76dd55 100644 --- a/client/src/pages/presentationEditor/components/slideSettingsComponents/SlideType.tsx +++ b/client/src/pages/presentationEditor/components/slideSettingsComponents/SlideType.tsx @@ -5,6 +5,7 @@ import { DialogContent, DialogContentText, DialogTitle, + FormControl, InputLabel, ListItem, MenuItem, @@ -16,7 +17,7 @@ import React, { useState } from 'react' import { getEditorCompetition } from '../../../../actions/editor' import { useAppDispatch } from '../../../../hooks' import { RichSlide } from '../../../../interfaces/ApiRichModels' -import { Center, FormControlDropdown, SlideTypeInputLabel } from '../styled' +import { Center, FirstItem } from '../styled' type SlideTypeProps = { activeSlide: RichSlide @@ -85,52 +86,55 @@ const SlideType = ({ activeSlide, competitionId }: SlideTypeProps) => { } } return ( - <ListItem> - <FormControlDropdown variant="outlined"> - <SlideTypeInputLabel>Sidtyp</SlideTypeInputLabel> - <Select fullWidth={true} value={activeSlide?.questions[0]?.type_id || 0} label="Sidtyp"> - <MenuItem value={0}> - <Typography variant="button" onClick={() => openSlideTypeDialog(0)}> - Informationssida - </Typography> - </MenuItem> - <MenuItem value={1}> - <Typography variant="button" onClick={() => openSlideTypeDialog(1)}> - Skriftlig fråga - </Typography> - </MenuItem> - <MenuItem value={2}> - <Typography variant="button" onClick={() => openSlideTypeDialog(2)}> - Praktisk fråga - </Typography> - </MenuItem> - <MenuItem value={3}> - <Typography variant="button" onClick={() => openSlideTypeDialog(3)}> - Flervalsfråga - </Typography> - </MenuItem> - </Select> - </FormControlDropdown> - <Dialog open={slideTypeDialog} onClose={closeSlideTypeDialog}> - <Center> - <DialogTitle color="secondary">Varning!</DialogTitle> - </Center> - <DialogContent> - <DialogContentText> - Om du ändrar sidtypen kommer eventuella frågeinställningar gå förlorade. Det inkluderar: frågans namn, poäng - och svarsalternativ.{' '} - </DialogContentText> - </DialogContent> - <DialogActions> - <Button onClick={closeSlideTypeDialog} color="secondary"> - Avbryt - </Button> - <Button onClick={updateSlideType} color="primary"> - Bekräfta - </Button> - </DialogActions> - </Dialog> - </ListItem> + <FirstItem> + <ListItem> + <FormControl fullWidth variant="outlined"> + <InputLabel>Sidtyp</InputLabel> + <Select fullWidth={true} value={activeSlide?.questions[0]?.type_id || 0} label="Sidtyp"> + <MenuItem value={0}> + <Typography variant="button" onClick={() => openSlideTypeDialog(0)}> + Informationssida + </Typography> + </MenuItem> + <MenuItem value={1}> + <Typography variant="button" onClick={() => openSlideTypeDialog(1)}> + Skriftlig fråga + </Typography> + </MenuItem> + <MenuItem value={2}> + <Typography variant="button" onClick={() => openSlideTypeDialog(2)}> + Praktisk fråga + </Typography> + </MenuItem> + <MenuItem value={3}> + <Typography variant="button" onClick={() => openSlideTypeDialog(3)}> + Flervalsfråga + </Typography> + </MenuItem> + </Select> + </FormControl> + + <Dialog open={slideTypeDialog} onClose={closeSlideTypeDialog}> + <Center> + <DialogTitle color="secondary">Varning!</DialogTitle> + </Center> + <DialogContent> + <DialogContentText> + Om du ändrar sidtypen kommer eventuella frågeinställningar gå förlorade. Det inkluderar: frågans namn, + poäng och svarsalternativ.{' '} + </DialogContentText> + </DialogContent> + <DialogActions> + <Button onClick={closeSlideTypeDialog} color="secondary"> + Avbryt + </Button> + <Button onClick={updateSlideType} color="primary"> + Bekräfta + </Button> + </DialogActions> + </Dialog> + </ListItem> + </FirstItem> ) } diff --git a/client/src/pages/presentationEditor/components/slideSettingsComponents/Texts.tsx b/client/src/pages/presentationEditor/components/slideSettingsComponents/Texts.tsx index dd0b40845e3252ccb2fed874d30a03b19498f915..39cf09af3ca31b73f30c258570e28365117a4282 100644 --- a/client/src/pages/presentationEditor/components/slideSettingsComponents/Texts.tsx +++ b/client/src/pages/presentationEditor/components/slideSettingsComponents/Texts.tsx @@ -1,13 +1,12 @@ import { Divider, ListItem, ListItemText, Typography } from '@material-ui/core' import React from 'react' -import { useAppSelector } from '../../../../hooks' +import { useAppDispatch, useAppSelector } from '../../../../hooks' import { TextComponent } from '../../../../interfaces/ApiModels' import { RichSlide } from '../../../../interfaces/ApiRichModels' import { AddButton, Center, SettingsList, TextCard } from '../styled' import TextComponentEdit from '../TextComponentEdit' import axios from 'axios' import { getEditorCompetition } from '../../../../actions/editor' -import { useDispatch } from 'react-redux' type TextsProps = { activeSlide: RichSlide @@ -22,7 +21,7 @@ const Texts = ({ activeSlide, competitionId }: TextsProps) => { ?.components.filter((component) => component.type_id === 1) as TextComponent[] ) - const dispatch = useDispatch() + const dispatch = useAppDispatch() const handleAddText = async () => { if (activeSlide) { await axios.post(`/api/competitions/${competitionId}/slides/${activeSlide?.id}/components`, { diff --git a/client/src/pages/presentationEditor/components/styled.tsx b/client/src/pages/presentationEditor/components/styled.tsx index af2108d63ef518819ea5aca0e925c528cba48e2b..7255c2bbc8a57475662191cd57428986a105348b 100644 --- a/client/src/pages/presentationEditor/components/styled.tsx +++ b/client/src/pages/presentationEditor/components/styled.tsx @@ -54,25 +54,15 @@ export const ToolbarPadding = styled.div` padding-top: 55px; ` -export const FormControlDropdown = styled(FormControl)` - width: 100%; - margin-top: 10px; -` - -export const SlideTypeInputLabel = styled(InputLabel)` +export const FirstItem = styled.div` width: 100%; + padding-top: 10px; ` export const AlternativeTextField = styled(TextField)` width: 87%; ` -export const NoPadding = styled.div` - padding: 0; - height: 100%; - width: 100%; -` - export const Center = styled.div` display: flex; justify-content: center; @@ -81,16 +71,13 @@ export const Center = styled.div` width: 100%; ` -export const SlidePanel = styled.div` +export const PanelContainer = styled.div` padding: 10px; width: 100%; ` export const AddButton = styled(Typography)` - padding-left: 8px; - padding-right: 8px; - padding-top: 7px; - padding-bottom: 7px; + padding: 7px 8px 7px 8px; ` export const ImportedImage = styled.img` @@ -103,7 +90,7 @@ export const Clickable = styled.div` ` export const AddImageButton = styled.label` - padding: 0; + padding: 8px 13px 8px 13px; cursor: 'pointer'; display: flex; justify-content: center; diff --git a/client/src/pages/views/JudgeViewPage.tsx b/client/src/pages/views/JudgeViewPage.tsx index 0d16daaccec0f8b496ae10f62e45354e9b39f829..de5abe40f2b3a194a1120963c30ad3ba5907ea4e 100644 --- a/client/src/pages/views/JudgeViewPage.tsx +++ b/client/src/pages/views/JudgeViewPage.tsx @@ -1,7 +1,6 @@ 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' import { getPresentationCompetition, setCurrentSlide, setPresentationCode } from '../../actions/presentation' import { useAppDispatch, useAppSelector } from '../../hooks' import { ViewParams } from '../../interfaces/ViewParams'