add images to previews

This commit is contained in:
nflnkr 2023-12-06 19:41:17 +03:00
parent 27a76b3011
commit 9e92209088
6 changed files with 197 additions and 176 deletions

@ -29,8 +29,6 @@ export type QuizResultsType = true | null;
export interface QuizConfig { export interface QuizConfig {
type: QuizType; type: QuizType;
logo: string | null;
originalLogo: string | null;
noStartPage: boolean; noStartPage: boolean;
startpageType: QuizStartpageType; startpageType: QuizStartpageType;
results: QuizResultsType; results: QuizResultsType;
@ -41,6 +39,8 @@ export interface QuizConfig {
position: QuizStartpageAlignType; position: QuizStartpageAlignType;
favIcon: string | null; favIcon: string | null;
originalFavIcon: string | null; originalFavIcon: string | null;
logo: string | null;
originalLogo: string | null;
background: { background: {
type: null | "image" | "video"; type: null | "image" | "video";
desktop: string | null; desktop: string | null;
@ -63,8 +63,6 @@ export interface QuizConfig {
export const defaultQuizConfig: QuizConfig = { export const defaultQuizConfig: QuizConfig = {
type: null, type: null,
logo: null,
originalLogo: null,
noStartPage: false, noStartPage: false,
startpageType: null, startpageType: null,
results: null, results: null,
@ -75,6 +73,8 @@ export const defaultQuizConfig: QuizConfig = {
position: "left", position: "left",
favIcon: null, favIcon: null,
originalFavIcon: null, originalFavIcon: null,
logo: null,
originalLogo: null,
background: { background: {
type: null, type: null,
desktop: null, desktop: null,

@ -582,22 +582,22 @@ export default function StartPageSettings() {
<DropZone <DropZone
text={"5 MB максимум"} text={"5 MB максимум"}
sx={{ maxWidth: "300px" }} sx={{ maxWidth: "300px" }}
imageUrl={quiz.config.logo} imageUrl={quiz.config.startpage.logo}
originalImageUrl={quiz.config.originalLogo} originalImageUrl={quiz.config.startpage.originalLogo}
onImageUploadClick={file => { onImageUploadClick={file => {
uploadQuizImage(quiz.id, file, (quiz, url) => { uploadQuizImage(quiz.id, file, (quiz, url) => {
quiz.config.logo = url; quiz.config.startpage.logo = url;
quiz.config.originalLogo = url; quiz.config.startpage.originalLogo = url;
}); });
}} }}
onImageSaveClick={file => { onImageSaveClick={file => {
uploadQuizImage(quiz.id, file, (quiz, url) => { uploadQuizImage(quiz.id, file, (quiz, url) => {
quiz.config.logo = url; quiz.config.startpage.logo = url;
}); });
}} }}
onDeleteClick={() => { onDeleteClick={() => {
updateQuiz(quiz.id, quiz => { updateQuiz(quiz.id, quiz => {
quiz.config.logo = null; quiz.config.startpage.logo = null;
}); });
}} }}
/> />
@ -664,22 +664,22 @@ export default function StartPageSettings() {
<DropZone <DropZone
text={"5 MB максимум"} text={"5 MB максимум"}
sx={{ maxWidth: "300px" }} sx={{ maxWidth: "300px" }}
imageUrl={quiz.config.logo} imageUrl={quiz.config.startpage.logo}
originalImageUrl={quiz.config.originalLogo} originalImageUrl={quiz.config.startpage.originalLogo}
onImageUploadClick={file => { onImageUploadClick={file => {
uploadQuizImage(quiz.id, file, (quiz, url) => { uploadQuizImage(quiz.id, file, (quiz, url) => {
quiz.config.logo = url; quiz.config.startpage.logo = url;
quiz.config.originalLogo = url; quiz.config.startpage.originalLogo = url;
}); });
}} }}
onImageSaveClick={file => { onImageSaveClick={file => {
uploadQuizImage(quiz.id, file, (quiz, url) => { uploadQuizImage(quiz.id, file, (quiz, url) => {
quiz.config.logo = url; quiz.config.startpage.logo = url;
}); });
}} }}
onDeleteClick={() => { onDeleteClick={() => {
updateQuiz(quiz.id, quiz => { updateQuiz(quiz.id, quiz => {
quiz.config.logo = null; quiz.config.startpage.logo = null;
}); });
}} }}
/> />

@ -219,9 +219,9 @@ export default function QuizPreviewLayout() {
} }
function QuestionPreviewComponent({ question }: { function QuestionPreviewComponent({ question }: {
question: AnyTypedQuizQuestion | UntypedQuizQuestion; question: AnyTypedQuizQuestion | UntypedQuizQuestion | undefined;
}) { }) {
if (question.type === null) return null; if (!question || question.type === null) return null;
switch (question.type) { switch (question.type) {
case "variant": return <Variant question={question} />; case "variant": return <Variant question={question} />;

@ -1,13 +1,13 @@
import { ChangeEvent, useState } from "react"; import { ChangeEvent, useState } from "react";
import { import {
Box, Box,
FormControl, FormControl,
FormControlLabel, FormControlLabel,
FormLabel, FormLabel,
Radio, Radio,
RadioGroup, RadioGroup,
Tooltip, Tooltip,
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import InfoIcon from "@icons/InfoIcon"; import InfoIcon from "@icons/InfoIcon";
@ -15,57 +15,68 @@ import InfoIcon from "@icons/InfoIcon";
import type { QuizQuestionVariant } from "model/questionTypes/variant"; import type { QuizQuestionVariant } from "model/questionTypes/variant";
interface Props { interface Props {
question: QuizQuestionVariant; question: QuizQuestionVariant;
} }
export default function Variant({ question }: Props) { export default function Variant({ question }: Props) {
const [value, setValue] = useState<string | null>(null); const [value, setValue] = useState<string | null>(null);
const handleChange = (event: ChangeEvent<HTMLInputElement>) => { const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setValue((event.target as HTMLInputElement).value); setValue((event.target as HTMLInputElement).value);
}; };
return ( return (
<FormControl fullWidth> <Box sx={{
<FormLabel id="quiz-question-radio-group" data-cy="question-title"> display: "flex",
{question.title} flexDirection: "column",
</FormLabel> gap: 1,
<RadioGroup }}>
aria-labelledby="quiz-question-radio-group" <Typography>{question.title}</Typography>
value={value} <RadioGroup
onChange={handleChange} aria-labelledby="quiz-question-radio-group"
> value={value}
{question.content.variants onChange={handleChange}
.filter(({ answer }) => answer) >
.map((variant, index) => ( {question.content.variants
<FormControlLabel .filter(({ answer }) => answer)
key={index} .map((variant, index) => (
value={variant.answer} <FormControlLabel
data-cy="variant-answer" key={index}
control={ value={variant.answer}
<Radio data-cy="variant-answer"
inputProps={{ control={
"data-cy": "variant-radio", <Radio
}} inputProps={{
/> "data-cy": "variant-radio",
} }}
label={ />
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}> }
<Typography> label={
{variant.answer} <Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
</Typography> <Typography>
{variant.hints && ( {variant.answer}
<Tooltip title={variant.hints} placement="right"> </Typography>
<Box> {variant.hints && (
<InfoIcon /> <Tooltip title={variant.hints} placement="right">
</Box> <Box>
</Tooltip> <InfoIcon />
)} </Box>
</Box> </Tooltip>
} )}
</Box>
}
/>
))}
</RadioGroup>
<img
src={question.content.back}
style={{
display: "block",
objectFit: "scale-down",
alignSelf: "start",
maxWidth: "100%",
}}
/> />
))} </Box>
</RadioGroup> );
</FormControl>
);
} }

@ -1,13 +1,13 @@
import { useState, ChangeEvent } from "react"; import { useState, ChangeEvent, useEffect } from "react";
import { import {
Box, Box,
FormControl, FormControl,
FormControlLabel, FormControlLabel,
FormLabel, FormLabel,
Radio, Radio,
RadioGroup, RadioGroup,
Tooltip, Tooltip,
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import InfoIcon from "@icons/InfoIcon"; import InfoIcon from "@icons/InfoIcon";
@ -16,103 +16,113 @@ import type { QuestionVariant } from "model/questionTypes/shared";
import type { QuizQuestionVarImg } from "model/questionTypes/varimg"; import type { QuizQuestionVarImg } from "model/questionTypes/varimg";
interface Props { interface Props {
question: QuizQuestionVarImg; question: QuizQuestionVarImg;
} }
export default function Varimg({ question }: Props) { export default function Varimg({ question }: Props) {
const [selectedVariantIndex, setSelectedVariantIndex] = useState<number>(-1); const [selectedVariantIndex, setSelectedVariantIndex] = useState<number>(-1);
const handleChange = (event: ChangeEvent<HTMLInputElement>) => { const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setSelectedVariantIndex( setSelectedVariantIndex(
question.content.variants.findIndex( question.content.variants.findIndex(
(variant) => variant.answer === event.target.value (variant) => variant.answer === event.target.value
) )
); );
}; };
const currentVariant: QuestionVariant | undefined = const currentVariant: QuestionVariant | undefined =
question.content.variants[selectedVariantIndex]; question.content.variants[selectedVariantIndex];
return ( return (
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
flexWrap: "wrap", flexWrap: "wrap",
gap: 2, gap: 2,
}}
>
<FormControl>
<FormLabel
id="quiz-question-radio-group"
data-cy="question-title"
>
{question.title}
</FormLabel>
<RadioGroup
aria-labelledby="quiz-question-radio-group"
value={currentVariant?.answer ?? ""}
onChange={handleChange}
>
{question.content.variants
.filter(({ answer }) => answer)
.map((variant, index) => (
<FormControlLabel
key={index}
value={variant.answer}
data-cy="variant-answer"
control={
<Radio
inputProps={{
"data-cy": "variant-radio",
}}
/>
}
label={
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<Typography>{variant.answer}</Typography>
{variant.hints && (
<Tooltip title={variant.hints} placement="right">
<Box>
<InfoIcon />
</Box>
</Tooltip>
)}
</Box>
}
/>
))}
</RadioGroup>
</FormControl>
<Box
sx={{
border: "1px solid #E3E3E3",
maxWidth: "400px",
display: "flex",
justifyContent: "center",
alignItems: "center",
borderRadius: "8px",
}}
>
{currentVariant?.extendedText ? (
<img
src={currentVariant.extendedText}
data-cy="variant-image"
alt="question variant"
style={{
width: "100%",
display: "block",
objectFit: "scale-down",
flexGrow: 1,
}} }}
/> >
) : ( <FormControl>
<Typography p={2}> <FormLabel
{selectedVariantIndex === -1 id="quiz-question-radio-group"
? "Выберите вариант" data-cy="question-title"
: "Картинка отсутствует"} >
</Typography> {question.title}
)} </FormLabel>
</Box> <RadioGroup
</Box> aria-labelledby="quiz-question-radio-group"
); value={currentVariant?.answer ?? ""}
onChange={handleChange}
>
{question.content.variants
.filter(({ answer }) => answer)
.map((variant, index) => (
<FormControlLabel
key={index}
value={variant.answer}
data-cy="variant-answer"
control={
<Radio
inputProps={{
"data-cy": "variant-radio",
}}
/>
}
label={
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<Typography>{variant.answer}</Typography>
{variant.hints && (
<Tooltip title={variant.hints} placement="right">
<Box>
<InfoIcon />
</Box>
</Tooltip>
)}
</Box>
}
/>
))}
</RadioGroup>
</FormControl>
<Box
sx={{
border: "1px solid #E3E3E3",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
{currentVariant ?
currentVariant.extendedText ? (
<img
src={currentVariant.extendedText}
data-cy="variant-image"
alt="question variant"
style={{
width: "100%",
display: "block",
objectFit: "scale-down",
flexGrow: 1,
}}
/>
) : (
<Typography p={2}>Картинка отсутствует</Typography>
) : question.content.back ? (
<img
src={question.content.back}
data-cy="variant-image"
alt="question variant"
style={{
width: "100%",
display: "block",
objectFit: "scale-down",
flexGrow: 1,
}}
/>
) : (
<Typography p={2}>Выберите вариант</Typography>
)
}
</Box>
</Box>
);
} }

@ -53,9 +53,9 @@ export default function QuizPreviewLayout() {
}} }}
> >
{quiz.config.startpage.background.type === "image" && {quiz.config.startpage.background.type === "image" &&
quiz.config.startpage.background.desktop && ( quiz.config.startpage.logo && (
<img <img
src={quiz.config.startpage.background.desktop} src={quiz.config.startpage.logo}
style={{ style={{
height: "30px", height: "30px",
maxWidth: "50px", maxWidth: "50px",