diff --git a/client/src/enum/ComponentTypes.ts b/client/src/enum/ComponentTypes.ts index c0aa738479a2c081ef0529bb6b4a317570b6841d..7ff75bd8d867762550dd9bcb6997038ac8d4b233 100644 --- a/client/src/enum/ComponentTypes.ts +++ b/client/src/enum/ComponentTypes.ts @@ -1,5 +1,5 @@ export enum ComponentTypes { Text = 1, Image, - QuestionAlternative, + Question, } diff --git a/client/src/interfaces/ApiModels.ts b/client/src/interfaces/ApiModels.ts index a6fa68a0e9b58dcc63ad67d29884bbf3e781a64a..6bc7aca9bcac7fe226313699ee0a2d06f95e924b 100644 --- a/client/src/interfaces/ApiModels.ts +++ b/client/src/interfaces/ApiModels.ts @@ -93,6 +93,16 @@ export interface TextComponent extends Component { font: string } -export interface QuestionAlternativeComponent extends Component { +export interface QuestionComponent extends Component { + id: number + x: number + y: number + w: number + h: number + slide_id: number + type_id: number + view_type_id: number + text: string + media: Media question_id: number } diff --git a/client/src/pages/presentationEditor/components/QuestionComponentDisplay.tsx b/client/src/pages/presentationEditor/components/QuestionComponentDisplay.tsx new file mode 100644 index 0000000000000000000000000000000000000000..0371991b55d13e2ebc99fd2c0ef45641b1f2ae2a --- /dev/null +++ b/client/src/pages/presentationEditor/components/QuestionComponentDisplay.tsx @@ -0,0 +1,19 @@ +import { Typography } from '@material-ui/core' +import React from 'react' +import { QuestionComponent } from '../../../interfaces/ApiModels' + +type QuestionComponentProps = { + component: QuestionComponent + width: number + height: number +} + +const QuestionComponentDisplay = ({ component, width, height }: QuestionComponentProps) => { + return ( + <div> + <Typography>Frågekomponent</Typography> + </div> + ) +} + +export default QuestionComponentDisplay diff --git a/client/src/pages/presentationEditor/components/RndComponent.tsx b/client/src/pages/presentationEditor/components/RndComponent.tsx index 77ed5de337f5ed620e77994cea2e512166d7b7d9..32470457b82aade246dfaa800b0496adfe64f0c2 100644 --- a/client/src/pages/presentationEditor/components/RndComponent.tsx +++ b/client/src/pages/presentationEditor/components/RndComponent.tsx @@ -4,13 +4,14 @@ 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, QuestionComponent, 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' +import QuestionComponentDisplay from './QuestionComponentDisplay' type RndComponentProps = { component: Component @@ -86,6 +87,16 @@ const RndComponent = ({ component, width, height, scale }: RndComponentProps) => /> </HoverContainer> ) + case ComponentTypes.Question: + return ( + <HoverContainer hover={hover}> + <QuestionComponentDisplay + height={currentSize.h * scale} + width={currentSize.w * scale} + component={component as QuestionComponent} + /> + </HoverContainer> + ) default: break } diff --git a/client/src/pages/presentationEditor/components/SlideSettings.tsx b/client/src/pages/presentationEditor/components/SlideSettings.tsx index d48b4565712d043d52d3b1e93e3633ec6b927d38..a39a95d4750f3bb56fb65dcb24669c51484b6557 100644 --- a/client/src/pages/presentationEditor/components/SlideSettings.tsx +++ b/client/src/pages/presentationEditor/components/SlideSettings.tsx @@ -36,13 +36,11 @@ const SlideSettings: React.FC = () => { </SettingsList> {activeSlide?.questions[0] && <QuestionSettings activeSlide={activeSlide} competitionId={competitionId} />} + { - // Choose answer alternatives depending on the slide type + // Choose answer alternatives, depending on the slide type } - {activeSlide?.questions[0]?.type_id === 1 && ( - <Instructions activeSlide={activeSlide} competitionId={competitionId} /> - )} - {activeSlide?.questions[0]?.type_id === 2 && ( + {(activeSlide?.questions[0]?.type_id === 1 || activeSlide?.questions[0]?.type_id === 2) && ( <Instructions activeSlide={activeSlide} competitionId={competitionId} /> )} {activeSlide?.questions[0]?.type_id === 3 && ( diff --git a/client/src/pages/presentationEditor/components/slideSettingsComponents/SlideType.tsx b/client/src/pages/presentationEditor/components/slideSettingsComponents/SlideType.tsx index bc251b91e092c05457db1b64bb8bbe566d76dd55..1c976e53298ba0a9bbabc5d3b9224f452bc15f97 100644 --- a/client/src/pages/presentationEditor/components/slideSettingsComponents/SlideType.tsx +++ b/client/src/pages/presentationEditor/components/slideSettingsComponents/SlideType.tsx @@ -15,8 +15,8 @@ import { import axios from 'axios' import React, { useState } from 'react' import { getEditorCompetition } from '../../../../actions/editor' -import { useAppDispatch } from '../../../../hooks' -import { RichSlide } from '../../../../interfaces/ApiRichModels' +import { useAppDispatch, useAppSelector } from '../../../../hooks' +import { RichQuestion, RichSlide } from '../../../../interfaces/ApiRichModels' import { Center, FirstItem } from '../styled' type SlideTypeProps = { @@ -30,6 +30,11 @@ const SlideType = ({ activeSlide, competitionId }: SlideTypeProps) => { // For "slide type" dialog const [selectedSlideType, setSelectedSlideType] = useState(0) const [slideTypeDialog, setSlideTypeDialog] = useState(false) + const components = useAppSelector( + (state) => state.editor.competition.slides.find((slide) => slide.id === state.editor.activeSlideId)?.components + ) + const questionComponentId = components?.find((qCompId) => qCompId.type_id === 3)?.id + const openSlideTypeDialog = (type_id: number) => { setSelectedSlideType(type_id) setSlideTypeDialog(true) @@ -41,6 +46,7 @@ const SlideType = ({ activeSlide, competitionId }: SlideTypeProps) => { const updateSlideType = async () => { closeSlideTypeDialog() if (activeSlide) { + deleteQuestionComponent(questionComponentId) if (activeSlide.questions[0] && activeSlide.questions[0].type_id !== selectedSlideType) { if (selectedSlideType === 0) { // Change slide type from a question type to information @@ -67,6 +73,7 @@ const SlideType = ({ activeSlide, competitionId }: SlideTypeProps) => { }) .then(() => { dispatch(getEditorCompetition(competitionId)) + createQuestionComponent() }) .catch(console.log) } @@ -80,11 +87,38 @@ const SlideType = ({ activeSlide, competitionId }: SlideTypeProps) => { }) .then(() => { dispatch(getEditorCompetition(competitionId)) + createQuestionComponent() }) .catch(console.log) } } } + + const createQuestionComponent = () => { + axios + .post(`/api/competitions/${competitionId}/slides/${activeSlide.id}/components`, { + x: 0, + y: 0, + w: 400, + h: 250, + type_id: 3, + view_type_id: 1, + question_id: activeSlide.questions[0].id, + }) + .then(() => { + dispatch(getEditorCompetition(competitionId)) + }) + .catch(console.log) + } + + const deleteQuestionComponent = (componentId: number | undefined) => { + if (componentId) { + axios + .delete(`/api/competitions/${competitionId}/slides/${activeSlide.id}/components/${componentId}`) + .catch(console.log) + } + } + return ( <FirstItem> <ListItem> diff --git a/client/src/pages/views/components/PresentationComponent.tsx b/client/src/pages/views/components/PresentationComponent.tsx index a41f7912469256a6e946522790f4f8203f8da60f..743db4bfe93664f805e015303374f2fd0c7225dc 100644 --- a/client/src/pages/views/components/PresentationComponent.tsx +++ b/client/src/pages/views/components/PresentationComponent.tsx @@ -1,12 +1,9 @@ -import { Typography } from '@material-ui/core' import React from 'react' import { Rnd } from 'react-rnd' import { ComponentTypes } from '../../../enum/ComponentTypes' -import { useAppSelector } from '../../../hooks' import { Component, ImageComponent, TextComponent } from '../../../interfaces/ApiModels' import ImageComponentDisplay from '../../presentationEditor/components/ImageComponentDisplay' import TextComponentDisplay from '../../presentationEditor/components/TextComponentDisplay' -import { SlideContainer } from './styled' type PresentationComponentProps = { component: Component diff --git a/server/app/apis/components.py b/server/app/apis/components.py index a1982763a5ec37b8bb02bb8e6a73e164355417a8..0368fc82a207d2bddf2990cab933c2611dafec67 100644 --- a/server/app/apis/components.py +++ b/server/app/apis/components.py @@ -11,7 +11,7 @@ schema = ComponentDTO.schema list_schema = ComponentDTO.list_schema component_parser_add = reqparse.RequestParser() -component_parser_add.add_argument("x", type=str, default=0, location="json") +component_parser_add.add_argument("x", type=int, default=0, location="json") component_parser_add.add_argument("y", type=int, default=0, location="json") component_parser_add.add_argument("w", type=int, default=1, location="json") component_parser_add.add_argument("h", type=int, default=1, location="json") @@ -22,7 +22,7 @@ component_parser_add.add_argument("media_id", type=int, default=None, location=" component_parser_add.add_argument("question_id", type=int, default=None, location="json") component_parser_edit = reqparse.RequestParser() -component_parser_edit.add_argument("x", type=str, default=sentinel, location="json") +component_parser_edit.add_argument("x", type=int, default=sentinel, location="json") component_parser_edit.add_argument("y", type=int, default=sentinel, location="json") component_parser_edit.add_argument("w", type=int, default=sentinel, location="json") component_parser_edit.add_argument("h", type=int, default=sentinel, location="json") diff --git a/server/populate.py b/server/populate.py index e0bb0bd94faf1b210069d7507d48e3f740157209..95983f96c1b1a00ef394826513e62ca84a9e146a 100644 --- a/server/populate.py +++ b/server/populate.py @@ -12,7 +12,7 @@ from app.database.models import City, QuestionType, Role def _add_items(): media_types = ["Image", "Video"] question_types = ["Boolean", "Multiple", "Text"] - component_types = ["Text", "Image"] + component_types = ["Text", "Image", "Question"] view_types = ["Team", "Judge", "Audience", "Operator"] roles = ["Admin", "Editor"]