From 52d8d623f370589e1518f951694f0c640b81a1d6 Mon Sep 17 00:00:00 2001 From: valentin-vrps Date: Fri, 5 Jul 2024 15:09:37 +0200 Subject: [PATCH] features improvement --- server/controllers/questions.ts | 14 +++- server/entities/question.ts | 11 ++- server/translations/defaultLocales.ts | 11 +-- server/xml/index.ts | 6 +- src/components/collaboration/FormFeedback.tsx | 13 +++- .../create/DiaporamaCard/DiaporamaCard.tsx | 12 +++- .../DiaporamaPlayer/DiaporamaPlayer.tsx | 2 +- .../create/DiaporamaPlayer/Frame.tsx | 8 ++- .../create/TitleCanvas/TitleCanvas.tsx | 70 ++++++++++++++++++- src/components/create/TitleCard/TitleCard.tsx | 11 ++- src/components/layout/Form/input.module.scss | 1 - src/pages/create/3-storyboard/edit.tsx | 6 +- src/pages/create/3-storyboard/index.tsx | 6 +- src/pages/create/3-storyboard/title.tsx | 6 +- src/pages/create/4-pre-mounting/edit.tsx | 6 +- src/pages/create/4-pre-mounting/index.tsx | 6 +- src/pages/create/6-result/index.tsx | 55 +++------------ types/models/question.type.ts | 2 +- 18 files changed, 166 insertions(+), 80 deletions(-) diff --git a/server/controllers/questions.ts b/server/controllers/questions.ts index 307cd80a..304ac17e 100644 --- a/server/controllers/questions.ts +++ b/server/controllers/questions.ts @@ -255,10 +255,20 @@ questionController.put({ path: '/:id', userType: UserType.CLASS }, async (req, r question.soundVolume = data.soundVolume !== undefined ? data.soundVolume : question.soundVolume; const dataStatus = data.status; logger.info(`dataStatus: ${dataStatus}`); - if (dataStatus !== undefined && dataStatus !== null) { + const previousStatus = question.status; + if (previousStatus === QuestionStatus.STORYBOARD && dataStatus === QuestionStatus.PREMOUNTING) { question.status = dataStatus; - question.feedback = [QuestionStatus.ONGOING, QuestionStatus.PREMOUNTING].includes(dataStatus) && data.feedback ? data.feedback : null; + question.feedbacks = null; + } else { + if (dataStatus !== undefined && dataStatus !== null) { + question.status = dataStatus; + question.feedbacks = + [QuestionStatus.ONGOING, QuestionStatus.PREMOUNTING].includes(dataStatus) && data.feedback + ? [...(question.feedbacks || []), data.feedback] + : question.feedbacks || []; + } } + await getRepository(Question).save(question); res.sendJSON(question); }); diff --git a/server/entities/question.ts b/server/entities/question.ts index 70f717ed..33561f1b 100644 --- a/server/entities/question.ts +++ b/server/entities/question.ts @@ -49,6 +49,13 @@ export class Question implements QuestionInterface { }) status: QuestionStatus; - @Column({ type: 'varchar', length: 2000, nullable: true }) - public feedback: string | null; + @Column({ + type: 'text', + nullable: true, + transformer: { + to: (value: string[] | null) => (value ? JSON.stringify(value) : null), + from: (value: string | null) => (value ? JSON.parse(value) : null), + }, + }) + public feedbacks: string[] | null; } diff --git a/server/translations/defaultLocales.ts b/server/translations/defaultLocales.ts index c3d02689..59a6b6ab 100644 --- a/server/translations/defaultLocales.ts +++ b/server/translations/defaultLocales.ts @@ -80,6 +80,11 @@ export const locales = { left: "gauche", center: "centre", right: "droite", + black: 'noir', + white: 'blanc', + red: 'rouge', + green: 'vert', + blue: 'bleu', //--- part4 --- part4_title: 'Prémontez votre <1>film', part4_subtitle1: 'Pour chaque séquence vous pouvez écrire et enregistrer une voix-off.', @@ -107,13 +112,8 @@ export const locales = { part6_subtitle1: 'À cette étape, vous pouvez pré-visualiser votre diaporama sonore achevé.', part6_pdf_button: 'Télécharger le storyboard', part6_mlt_button: 'Télécharger le fichier de montage', - part6_mp4_button: 'Générer votre vidéo', part6_mp4_download_button: 'Télécharger votre vidéo !', - part6_mp4_generate_button: 'Générer une nouvelle vidéo', part6_mp4_loading: 'Création de votre vidéo...', - part6_mp4_description_1: 'La génération de votre vidéo peut prendre du temps.', - part6_mp4_description_2: "Vous pouvez quitter et suivre à tout moment l'avancement du montage de votre vidéo sur cette page.", - part6_mp4_description_3: 'Votre vidéo sera disponible pendant 2 jours. Passé ce delai elle sera supprimée.', part6_mp4_user_disabled: 'Connectez-vous et créez un projet pour générer une vidéo.', part6_mp4_project_disabled: 'Créez un projet pour générer une vidéo.', part6_subtitle2: @@ -297,6 +297,7 @@ export const locales = { collaboration_form_feedback_btn_feedback: 'Envoyer le retour', collaboration_form_feedback_btn_ok: 'Valider le travail', collaboration_form_feedback_error: 'Veuillez renseigner un message de retour.', + collaboration_previous_feedbacks_label: 'Retours précédents', collaboration_form_feedback_label: 'Retours', collaboration_form_feedback_placeholder: 'Vos retours (Raccourcir la durée de la séquence, monter le son, ...)', collaboration_form_feedback_title: 'Travail à vérifier', diff --git a/server/xml/index.ts b/server/xml/index.ts index 33dc8f96..7fd21b6f 100644 --- a/server/xml/index.ts +++ b/server/xml/index.ts @@ -184,9 +184,9 @@ export function projectToMlt(allQuestions: Question[], project: Project, urlTran size: fontSize, weight: '500', style: 'normal', - fgcolour: '#000000', - bgcolour: '#ffffffff', - olcolour: '#ffffffff', + fgcolour: style.color || '#000000', + bgcolour: style.backgroundColor || '#ffffffff', + olcolour: style.backgroundColor || '#ffffffff', halign: 'center', valign: 'middle', mlt_service: 'dynamictext', diff --git a/src/components/collaboration/FormFeedback.tsx b/src/components/collaboration/FormFeedback.tsx index b3d9961d..651abab1 100644 --- a/src/components/collaboration/FormFeedback.tsx +++ b/src/components/collaboration/FormFeedback.tsx @@ -42,7 +42,7 @@ export const FormFeedback: React.FunctionComponent = ({ quest newQuestions[question.index] = { ...newQuestions[question.index], status, - feedback: feedbackData, + feedbacks: feedbackData ? [...(question.feedbacks ?? []), feedbackData] : question.feedbacks, }; const updatedProject = updateProject({ questions: newQuestions }); if (updatedProject) { @@ -87,6 +87,17 @@ export const FormFeedback: React.FunctionComponent = ({ quest {t('collaboration_form_feedback_title')} + {question.feedbacks && question.feedbacks.length > 0 && ( +
+
{t('collaboration_previous_feedbacks_label')} :
+
    + {question.feedbacks.map((feedbackItem, index) => ( +
  • {feedbackItem}
  • + ))} +
+
+ )} + (sequence.title !== null ? 'title' : 0); const [canvasRef, { height: canvasHeight }] = useResizeObserver(); - const baseButtonStyle: React.CSSProperties = { width: '100%', height: '100%', pointerEvents: isAuthorized ? 'auto' : 'none' }; const buttonStyle = React.useMemo(() => { const plan = frameIndex !== 'title' ? (sequence.plans || [])[frameIndex] : undefined; if (plan && plan.imageUrl) { @@ -48,6 +47,14 @@ export const DiaporamaCard = ({ projectId, questionIndex, sequence, isAuthorized } }, [sequence]); + const baseButtonStyle: React.CSSProperties = { + width: '100%', + height: '100%', + pointerEvents: isAuthorized ? 'auto' : 'none', + backgroundColor: style.backgroundColor || 'white', + color: style.color || 'black', + }; + const updateFrameIndex = React.useCallback(() => { setFrameIndex((prevFrame) => { let nextFrame: 'title' | number = prevFrame === 'title' ? 0 : prevFrame + 1; @@ -87,6 +94,9 @@ export const DiaporamaCard = ({ projectId, questionIndex, sequence, isAuthorized left: `${style.x ?? 15}%`, top: `${style.y ?? 30}%`, width: `${style.width ?? 70}%`, + backgroundColor: style.backgroundColor || 'white', + textAlign: style.textAlign || 'center', + color: style.color || 'black', } } > diff --git a/src/components/create/DiaporamaPlayer/DiaporamaPlayer.tsx b/src/components/create/DiaporamaPlayer/DiaporamaPlayer.tsx index 14091d58..18a4f9a1 100644 --- a/src/components/create/DiaporamaPlayer/DiaporamaPlayer.tsx +++ b/src/components/create/DiaporamaPlayer/DiaporamaPlayer.tsx @@ -542,7 +542,7 @@ export const DiaporamaPlayer = ({ setVolume(newValue); onUpdateVolume(newValue); }} - max={200} + max={300} min={0} orientation="vertical" /> diff --git a/src/components/create/DiaporamaPlayer/Frame.tsx b/src/components/create/DiaporamaPlayer/Frame.tsx index 39a4093a..a7435945 100644 --- a/src/components/create/DiaporamaPlayer/Frame.tsx +++ b/src/components/create/DiaporamaPlayer/Frame.tsx @@ -53,6 +53,9 @@ type FrameProps = { time: number; className?: string; }; + +type TextAlign = 'left' | 'center' | 'right'; + export const Frame = ({ questions, time, className }: FrameProps) => { const [canvasRef, { height: canvasHeight }] = useResizeObserver(); const currentFrame = getCurrentFrame(questions, time); @@ -62,7 +65,9 @@ export const Frame = ({ questions, time, className }: FrameProps) => { style={{ width: '100%', height: '100%', - backgroundColor: currentFrame !== null && currentFrame.kind === 'title' ? 'white' : 'unset', + backgroundColor: currentFrame !== null && currentFrame.kind === 'title' ? (String(currentFrame.style.backgroundColor) || 'white') : 'unset', + color: currentFrame !== null && currentFrame.kind === 'title' ? (String(currentFrame.style.color) || 'black') : 'black', + textAlign: currentFrame !== null && currentFrame.kind === 'title' ? currentFrame.style.textAlign as TextAlign || 'center' : 'center', }} ref={canvasRef} > @@ -81,6 +86,7 @@ export const Frame = ({ questions, time, className }: FrameProps) => { left: `${currentFrame.style.x ?? 15}%`, top: `${currentFrame.style.y ?? 30}%`, width: `${currentFrame.style.width ?? 70}%`, + textAlign: currentFrame.style.textAlign as TextAlign || 'center', } } > diff --git a/src/components/create/TitleCanvas/TitleCanvas.tsx b/src/components/create/TitleCanvas/TitleCanvas.tsx index 92b52f0f..7f3cec02 100644 --- a/src/components/create/TitleCanvas/TitleCanvas.tsx +++ b/src/components/create/TitleCanvas/TitleCanvas.tsx @@ -32,6 +32,8 @@ export function TitleCanvas({ title, onChange }: TitleCanvasProps) { const [fontFamily, setFontFamily] = React.useState(style.fontFamily || 'serif'); const [fontSize, setFontSize] = React.useState(style.fontSize || 8); // % const [textAlign, setTextAlign] = React.useState(style.textAlign || 'center'); + const [backgroundColor, setBackgroundColor] = React.useState(style.backgroundColor || 'white'); + const [color, setColor] = React.useState(style.color || 'black'); // relative pos const [textXPer, setTextXPer] = React.useState(style.x ?? 15); // % const [textYPer, setTextYPer] = React.useState(style.y ?? 30); // % @@ -46,10 +48,12 @@ export function TitleCanvas({ title, onChange }: TitleCanvasProps) { setTextYPer(style.y ?? 35); setTextWidthPer(style.width || 50); setTextAlign(style.textAlign || 'center'); + setBackgroundColor(style.backgroundColor || 'white'); + setColor(style.color || 'black'); }, [title, style]); const onChangeStyle = (newPartialSyle: Record) => { - onChange((prev) => ({ ...prev, style: JSON.stringify({ ...getStyle(prev.style), ...newPartialSyle }) })); + onChange((prev) => ({ ...prev, style: JSON.stringify({ ...getStyle(prev.style), ...newPartialSyle }) })); }; // Canvas ref with dimensions @@ -69,7 +73,7 @@ export function TitleCanvas({ title, onChange }: TitleCanvasProps) { if (textAreaRef.current) { setTextAreaRefHeight(textAreaRef.current.scrollHeight); } - }, [titleText, textWidthPer, canvasWidth, fontSize, fontFamily, textAlign]); // update textAreaRefHeight on title change. + }, [titleText, textWidthPer, canvasWidth, fontSize, fontFamily, textAlign, backgroundColor]); // update textAreaRefHeight on title change. // Absolute pos const { textX, textY, textWidth } = React.useMemo( @@ -141,7 +145,42 @@ export function TitleCanvas({ title, onChange }: TitleCanvasProps) { return (
- +
+ +
+
{t('medium')} +
+
+
{} } }, [title]); const [canvasRef, { height: canvasHeight }] = useResizeObserver(); - const buttonStyle: React.CSSProperties = { width: '100%', height: '100%', pointerEvents: canEdit ? 'auto' : 'none' }; + const buttonStyle: React.CSSProperties = { + width: '100%', + height: '100%', + pointerEvents: canEdit ? 'auto' : 'none', + backgroundColor: style ? style.backgroundColor : 'white', + color: style ? style.color : 'black', + }; return ( {} left: `${style.x ?? 15}%`, top: `${style.y ?? 30}%`, width: `${style.width ?? 70}%`, + backgroundColor: style.backgroundColor || 'white', + textAlign: style.textAlign || 'center', + color: style.color || 'black', } } > diff --git a/src/components/layout/Form/input.module.scss b/src/components/layout/Form/input.module.scss index 4bc4fe17..55131e72 100644 --- a/src/components/layout/Form/input.module.scss +++ b/src/components/layout/Form/input.module.scss @@ -3,7 +3,6 @@ .inputContainer { display: block; position: relative; - width: 300px; &--is-full-width { width: 100%; diff --git a/src/pages/create/3-storyboard/edit.tsx b/src/pages/create/3-storyboard/edit.tsx index 95a9cd1e..bc00bd38 100644 --- a/src/pages/create/3-storyboard/edit.tsx +++ b/src/pages/create/3-storyboard/edit.tsx @@ -154,7 +154,7 @@ const EditPlan = () => { const { user } = React.useContext(userContext); const isStudent = user?.type === UserType.STUDENT; const [showButtonFeedback, setShowButtonFeedback] = React.useState( - (isStudent && sequence && sequence.feedback && QuestionStatus.ONGOING === sequence.status) as boolean, + (isStudent && sequence && sequence.feedbacks && QuestionStatus.ONGOING === sequence.status) as boolean, ); const [showFeedback, setShowFeedback] = React.useState(false); const imageUrl = React.useMemo(() => { @@ -165,7 +165,7 @@ const EditPlan = () => { }, [imageBlob, plan]); React.useEffect(() => { - if (isStudent && sequence && sequence.feedback && QuestionStatus.ONGOING === sequence.status) { + if (isStudent && sequence && sequence.feedbacks && QuestionStatus.ONGOING === sequence.status) { setShowButtonFeedback(true); } }, [isStudent, sequence]); @@ -531,7 +531,7 @@ const EditPlan = () => { setShowFeedback(false)} - feedback={sequence && sequence.feedback ? sequence.feedback : ''} + feedback={sequence && sequence.feedbacks && sequence.feedbacks.length > 0 ? sequence.feedbacks[sequence.feedbacks.length - 1] : ''} /> ); diff --git a/src/pages/create/3-storyboard/index.tsx b/src/pages/create/3-storyboard/index.tsx index ad00d682..a1604f02 100644 --- a/src/pages/create/3-storyboard/index.tsx +++ b/src/pages/create/3-storyboard/index.tsx @@ -75,7 +75,7 @@ const Scenario = ({ const plans = React.useMemo(() => sequence.plans || [], [sequence]); const [showFeedback, setShowFeedback] = React.useState(false); - const showButtonFeedback = isStudent && sequence.feedback && QuestionStatus.ONGOING === sequence.status; + const showButtonFeedback = isStudent && sequence.feedbacks && QuestionStatus.ONGOING === sequence.status; const studentColor = COLORS[sequenceIndex]; const { project, isLoading: isProjectLoading, questions, updateProject } = useCurrentProject(); @@ -267,7 +267,9 @@ const Scenario = ({ setShowFeedback(false)} - feedback={sequence && sequence.feedback ? sequence.feedback : ''} + feedback={ + sequence && sequence.feedbacks && sequence.feedbacks.length > 0 ? sequence.feedbacks[sequence.feedbacks.length - 1] : '' + } />
{isCollaborationActive && !isStudent && sequence.status === QuestionStatus.STORYBOARD && ( diff --git a/src/pages/create/3-storyboard/title.tsx b/src/pages/create/3-storyboard/title.tsx index a5d269d6..317dd2bb 100644 --- a/src/pages/create/3-storyboard/title.tsx +++ b/src/pages/create/3-storyboard/title.tsx @@ -71,12 +71,12 @@ const TitlePlan = () => { const isStudent = user?.type === UserType.STUDENT; const [showButtonFeedback, setShowButtonFeedback] = React.useState( - (isStudent && sequence && sequence.feedback && QuestionStatus.ONGOING === sequence.status) as boolean, + (isStudent && sequence && sequence.feedbacks && QuestionStatus.ONGOING === sequence.status) as boolean, ); const [showFeedback, setShowFeedback] = React.useState(false); React.useEffect(() => { - if (isStudent && sequence && sequence.feedback && QuestionStatus.ONGOING === sequence.status) { + if (isStudent && sequence && sequence.feedbacks && QuestionStatus.ONGOING === sequence.status) { setShowButtonFeedback(true); } }, [isStudent, sequence]); @@ -165,7 +165,7 @@ const TitlePlan = () => { setShowFeedback(false)} - feedback={sequence && sequence.feedback ? sequence.feedback : ''} + feedback={sequence && sequence.feedbacks && sequence.feedbacks.length > 0 ? sequence.feedbacks[sequence.feedbacks.length - 1] : ''} /> ); diff --git a/src/pages/create/4-pre-mounting/edit.tsx b/src/pages/create/4-pre-mounting/edit.tsx index f51c5a42..e5964f86 100644 --- a/src/pages/create/4-pre-mounting/edit.tsx +++ b/src/pages/create/4-pre-mounting/edit.tsx @@ -83,12 +83,12 @@ const PreMountSequence = () => { const { user } = React.useContext(userContext); const isStudent = user?.type === UserType.STUDENT; const [showButtonFeedback, setShowButtonFeedback] = React.useState( - (isStudent && sequence && sequence.feedback && QuestionStatus.PREMOUNTING === sequence.status) as boolean, + (isStudent && sequence && sequence.feedbacks && QuestionStatus.PREMOUNTING === sequence.status) as boolean, ); const [showFeedback, setShowFeedback] = React.useState(false); React.useEffect(() => { - if (isStudent && sequence && sequence.feedback && QuestionStatus.PREMOUNTING === sequence.status) { + if (isStudent && sequence && sequence.feedbacks && QuestionStatus.PREMOUNTING === sequence.status) { setShowButtonFeedback(true); } }, [isStudent, sequence]); @@ -337,7 +337,7 @@ const PreMountSequence = () => { setShowFeedback(false)} - feedback={sequence && sequence.feedback ? sequence.feedback : ''} + feedback={sequence && sequence.feedbacks && sequence.feedbacks.length > 0 ? sequence.feedbacks[sequence.feedbacks.length - 1] : ''} /> ); diff --git a/src/pages/create/4-pre-mounting/index.tsx b/src/pages/create/4-pre-mounting/index.tsx index 453466f1..a8c46349 100644 --- a/src/pages/create/4-pre-mounting/index.tsx +++ b/src/pages/create/4-pre-mounting/index.tsx @@ -85,7 +85,7 @@ const PreMountingPage = () => { {questions.map((q, index) => { if (isStudent && sequencyId !== q.id) return null; const hasBeenEdited = q.title !== null || (q.plans || []).some((plan) => plan.description || plan.imageUrl); - const showButtonFeedback = isStudent && q.id === sequencyId && q.feedback && QuestionStatus.PREMOUNTING === q.status; + const showButtonFeedback = isStudent && q.id === sequencyId && q.feedbacks && QuestionStatus.PREMOUNTING === q.status; return (
@@ -105,12 +105,12 @@ const PreMountingPage = () => { /> </div> ) : ( - <p>{t('part4_placeholder')}</p> + <p style={{ marginTop: '1rem'}}>{t('part4_placeholder')}</p> )} <FeedbackModal isOpen={showFeedback} onClose={() => setShowFeedback(false)} - feedback={q && q.feedback ? q.feedback : ''} + feedback={q && q.feedbacks && q.feedbacks.length > 0 ? q.feedbacks[q.feedbacks.length - 1] : ''} /> </div> ); diff --git a/src/pages/create/6-result/index.tsx b/src/pages/create/6-result/index.tsx index 90e623ad..777f4342 100644 --- a/src/pages/create/6-result/index.tsx +++ b/src/pages/create/6-result/index.tsx @@ -12,7 +12,6 @@ import { Button } from 'src/components/layout/Button'; import { Container } from 'src/components/layout/Container'; import { Flex } from 'src/components/layout/Flex'; import { LinearProgress } from 'src/components/layout/LinearProgress'; -import { Modal } from 'src/components/layout/Modal'; import { Tooltip } from 'src/components/layout/Tooltip'; import { Title, Text } from 'src/components/layout/Typography'; import { Steps } from 'src/components/navigation/Steps'; @@ -81,7 +80,6 @@ const ResultPage = () => { const { isCollaborationActive } = useCollaboration(); const { socket, connectTeacher } = useSocket(); const [isLoading, setIsLoading] = React.useState(false); - const [isVideoModalOpen, setIsVideoModalOpen] = React.useState(false); const { projectVideo, isLoading: isLoadingProjectVideo, @@ -164,9 +162,16 @@ const ResultPage = () => { data, }, { - onSettled: () => { - setIsVideoModalOpen(false); + onSuccess: (data) => { setIsDownloading(true); + if (data && data.url) { + const a = document.createElement('a'); + a.href = data.url; + a.download = 'project_video.mp4'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + } }, onError: () => { sendToast({ message: t('unknown_error'), type: 'error' }); @@ -175,7 +180,6 @@ const ResultPage = () => { ); }; - const videoUrl = projectVideo?.url; const videoProgress = projectVideo?.progress; const hasProject = project !== undefined && project.id !== 0; @@ -221,22 +225,6 @@ const ResultPage = () => { <div>loading</div> ) : ( <> - {videoUrl && ( - <> - <Button - label={t('part6_mp4_download_button')} - as="a" - href={videoUrl} - className="full-width" - variant="contained" - color="secondary" - style={{ width: '100%' }} - leftIcon={<VideoIcon style={{ marginRight: '10px', width: '24px', height: '24px' }} />} - download - ></Button> - <Or /> - </> - )} {videoProgress && videoProgress !== 100 ? ( <div style={{ @@ -261,13 +249,11 @@ const ResultPage = () => { hasArrow > <Button - label={t(videoUrl ? 'part6_mp4_generate_button' : 'part6_mp4_button')} + label={t('part6_mp4_download_button')} className="full-width" variant="contained" color="secondary" - onClick={() => { - setIsVideoModalOpen(true); - }} + onClick={generateMP4} disabled={user === null || !hasProject} style={{ width: '100%' }} leftIcon={<VideoIcon style={{ marginRight: '10px', width: '24px', height: '24px' }} />} @@ -287,25 +273,6 @@ const ResultPage = () => { style={{ width: '100%' }} ></Button> </Flex> - <Modal - isOpen={isVideoModalOpen} - onClose={() => { - setIsVideoModalOpen(false); - }} - isLoading={createProjectVideoMutation.isLoading} - title={t('part6_mp4_button')} - confirmLabel={t('generate')} - onConfirm={generateMP4} - width="md" - isFullWidth - confirmLevel="secondary" - > - <ul style={{ margin: 0 }}> - <li style={{ marginBottom: '0.5rem' }}>{t('part6_mp4_description_1')}</li> - <li style={{ marginBottom: '0.5rem' }}>{t('part6_mp4_description_2')}</li> - <li style={{ marginBottom: '0.5rem' }}>{t('part6_mp4_description_3')}</li> - </ul> - </Modal> </div> <Loader isLoading={isLoading} /> </Container> diff --git a/types/models/question.type.ts b/types/models/question.type.ts index e6029f19..77e2aa41 100644 --- a/types/models/question.type.ts +++ b/types/models/question.type.ts @@ -22,7 +22,7 @@ export interface Question { soundUrl: string | null; soundVolume: number | null; status?: QuestionStatus; - feedback?: string | null; + feedbacks?: string[] | null; } export interface QuestionTemplate {