simplify question variant types
This commit is contained in:
parent
9c438de1f9
commit
f39ffb9c23
@ -18,7 +18,8 @@ export const QUIZ_QUESTION_EMOJI: Omit<QuizQuestionEmoji, "id" | "backendId"> =
|
||||
id: nanoid(),
|
||||
answer: "",
|
||||
extendedText: "",
|
||||
hints: ""
|
||||
hints: "",
|
||||
originalImageUrl: "",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@ -13,6 +13,6 @@ export const QUIZ_QUESTION_SELECT: Omit<QuizQuestionSelect, "id" | "backendId">
|
||||
innerNameCheck: false,
|
||||
innerName: "",
|
||||
default: "",
|
||||
variants: [{ id: nanoid(), answer: "", extendedText: "", hints: "" }],
|
||||
variants: [{ id: nanoid(), answer: "", extendedText: "", hints: "", originalImageUrl: "" }],
|
||||
},
|
||||
};
|
||||
|
||||
@ -14,6 +14,6 @@ export const QUIZ_QUESTION_VARIANT: Omit<QuizQuestionVariant, "id" | "backendId"
|
||||
innerNameCheck: false,
|
||||
required: false,
|
||||
innerName: "",
|
||||
variants: [{ id: nanoid(), answer: "", extendedText: "", hints: "" }],
|
||||
variants: [{ id: nanoid(), answer: "", extendedText: "", hints: "", originalImageUrl: "" }],
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type {
|
||||
ImageQuestionVariant,
|
||||
QuestionBranchingRule,
|
||||
QuestionHint,
|
||||
QuestionVariant,
|
||||
QuizQuestionBase
|
||||
} from "./shared";
|
||||
|
||||
@ -25,7 +25,7 @@ export interface QuizQuestionImages extends QuizQuestionBase {
|
||||
/** Чекбокс "Необязательный вопрос" */
|
||||
required: boolean;
|
||||
/** Варианты (картинки) */
|
||||
variants: ImageQuestionVariant[];
|
||||
variants: QuestionVariant[];
|
||||
hint: QuestionHint;
|
||||
rule: QuestionBranchingRule;
|
||||
back: string;
|
||||
|
||||
@ -40,12 +40,9 @@ export type QuestionVariant = {
|
||||
hints: string;
|
||||
/** Дополнительное поле для текста, emoji, ссылки на картинку */
|
||||
extendedText: string;
|
||||
};
|
||||
|
||||
export interface ImageQuestionVariant extends QuestionVariant {
|
||||
/** Оригинал изображения (до кропа) */
|
||||
originalImageUrl: string;
|
||||
}
|
||||
};
|
||||
|
||||
export interface QuizQuestionBase {
|
||||
backendId: number;
|
||||
@ -89,7 +86,7 @@ export type AnyQuizQuestion =
|
||||
// | QuizQuestionInitial;
|
||||
|
||||
type FilterQuestionsWithVariants<T> = T extends {
|
||||
content: { variants: QuestionVariant[] | ImageQuestionVariant[]; };
|
||||
content: { variants: QuestionVariant[]; };
|
||||
} ? T : never;
|
||||
|
||||
export type QuizQuestionsWithVariants = FilterQuestionsWithVariants<AnyQuizQuestion>;
|
||||
@ -100,9 +97,5 @@ export const createQuestionVariant: () => QuestionVariant = () => ({
|
||||
answer: "",
|
||||
extendedText: "",
|
||||
hints: "",
|
||||
});
|
||||
|
||||
export const createQuestionImageVariant: () => ImageQuestionVariant = () => ({
|
||||
...createQuestionVariant(),
|
||||
originalImageUrl: "",
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type {
|
||||
ImageQuestionVariant,
|
||||
QuestionBranchingRule,
|
||||
QuestionHint,
|
||||
QuestionVariant,
|
||||
QuizQuestionBase
|
||||
} from "./shared";
|
||||
|
||||
@ -16,7 +16,7 @@ export interface QuizQuestionVarImg extends QuizQuestionBase {
|
||||
innerName: string;
|
||||
/** Чекбокс "Необязательный вопрос" */
|
||||
required: boolean;
|
||||
variants: ImageQuestionVariant[];
|
||||
variants: QuestionVariant[];
|
||||
hint: QuestionHint;
|
||||
rule: QuestionBranchingRule;
|
||||
back: string;
|
||||
|
||||
@ -16,14 +16,13 @@ import { addQuestionVariant, deleteQuestionVariant, setQuestionVariantField } fr
|
||||
import type { KeyboardEvent, ReactNode } from "react";
|
||||
import { useState } from "react";
|
||||
import { Draggable } from "react-beautiful-dnd";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import type { ImageQuestionVariant, QuestionVariant } from "../../../model/questionTypes/shared";
|
||||
import type { QuestionVariant } from "../../../model/questionTypes/shared";
|
||||
|
||||
|
||||
type AnswerItemProps = {
|
||||
index: number;
|
||||
questionId: string;
|
||||
variant: QuestionVariant | ImageQuestionVariant;
|
||||
variant: QuestionVariant;
|
||||
largeCheck: boolean;
|
||||
additionalContent?: ReactNode;
|
||||
additionalMobile?: ReactNode;
|
||||
@ -40,7 +39,7 @@ export const AnswerItem = ({
|
||||
const theme = useTheme();
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(790));
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
||||
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
@ -73,7 +72,7 @@ export const AnswerItem = ({
|
||||
placeholder={"Добавьте ответ"}
|
||||
multiline={largeCheck}
|
||||
onChange={({ target }) => {
|
||||
setQuestionVariantField(questionId, variant.id, "answer", target.value)
|
||||
setQuestionVariantField(questionId, variant.id, "answer", target.value);
|
||||
}}
|
||||
onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (event.code === "Enter" && !largeCheck) {
|
||||
|
||||
@ -3,47 +3,47 @@ import { reorderQuestionVariants } from "@root/questions/actions";
|
||||
import { type ReactNode } from "react";
|
||||
import type { DropResult } from "react-beautiful-dnd";
|
||||
import { DragDropContext, Droppable } from "react-beautiful-dnd";
|
||||
import type { ImageQuestionVariant, QuestionVariant, QuizQuestionsWithVariants } from "../../../model/questionTypes/shared";
|
||||
import type { QuestionVariant, QuizQuestionsWithVariants } from "../../../model/questionTypes/shared";
|
||||
import { AnswerItem } from "./AnswerItem";
|
||||
|
||||
|
||||
type AnswerDraggableListProps = {
|
||||
question: QuizQuestionsWithVariants;
|
||||
additionalContent?: (variant: QuestionVariant | ImageQuestionVariant, index: number) => ReactNode;
|
||||
additionalMobile?: (variant: QuestionVariant | ImageQuestionVariant, index: number) => ReactNode;
|
||||
question: QuizQuestionsWithVariants;
|
||||
additionalContent?: (variant: QuestionVariant, index: number) => ReactNode;
|
||||
additionalMobile?: (variant: QuestionVariant, index: number) => ReactNode;
|
||||
};
|
||||
|
||||
export const AnswerDraggableList = ({
|
||||
question,
|
||||
additionalContent,
|
||||
additionalMobile,
|
||||
question,
|
||||
additionalContent,
|
||||
additionalMobile,
|
||||
}: AnswerDraggableListProps) => {
|
||||
const onDragEnd = ({ destination, source }: DropResult) => {
|
||||
if (destination) {
|
||||
reorderQuestionVariants(question.id, source.index, destination.index);
|
||||
}
|
||||
};
|
||||
const onDragEnd = ({ destination, source }: DropResult) => {
|
||||
if (destination) {
|
||||
reorderQuestionVariants(question.id, source.index, destination.index);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<DragDropContext onDragEnd={onDragEnd}>
|
||||
<Droppable droppableId="droppable-answer-list">
|
||||
{(provided) => (
|
||||
<Box ref={provided.innerRef} {...provided.droppableProps}>
|
||||
{question.content.variants.map((variant, index) => (
|
||||
<AnswerItem
|
||||
key={variant.id}
|
||||
index={index}
|
||||
questionId={question.id}
|
||||
largeCheck={("largeCheck" in question.content) ? question.content.largeCheck : false}
|
||||
variant={variant}
|
||||
additionalContent={additionalContent?.(variant, index)}
|
||||
additionalMobile={additionalMobile?.(variant, index)}
|
||||
/>
|
||||
))}
|
||||
{provided.placeholder}
|
||||
</Box>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
);
|
||||
return (
|
||||
<DragDropContext onDragEnd={onDragEnd}>
|
||||
<Droppable droppableId="droppable-answer-list">
|
||||
{(provided) => (
|
||||
<Box ref={provided.innerRef} {...provided.droppableProps}>
|
||||
{question.content.variants.map((variant, index) => (
|
||||
<AnswerItem
|
||||
key={variant.id}
|
||||
index={index}
|
||||
questionId={question.id}
|
||||
largeCheck={("largeCheck" in question.content) ? question.content.largeCheck : false}
|
||||
variant={variant}
|
||||
additionalContent={additionalContent?.(variant, index)}
|
||||
additionalMobile={additionalMobile?.(variant, index)}
|
||||
/>
|
||||
))}
|
||||
{provided.placeholder}
|
||||
</Box>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
);
|
||||
};
|
||||
|
||||
@ -2,14 +2,13 @@ import { questionApi } from "@api/question";
|
||||
import { devlog } from "@frontend/kitui";
|
||||
import { questionToEditQuestionRequest } from "@model/question/edit";
|
||||
import { QuestionType, RawQuestion, rawQuestionToQuestion } from "@model/question/question";
|
||||
import { AnyQuizQuestion, ImageQuestionVariant, QuestionVariant, createQuestionImageVariant, createQuestionVariant } from "@model/questionTypes/shared";
|
||||
import { AnyQuizQuestion, QuestionVariant, createQuestionVariant } from "@model/questionTypes/shared";
|
||||
import { produce } from "immer";
|
||||
import { nanoid } from "nanoid";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
import { isAxiosCanceledError } from "../../utils/isAxiosCanceledError";
|
||||
import { notReachable } from "../../utils/notReachable";
|
||||
import { RequestQueue } from "../../utils/requestQueue";
|
||||
import { QuestionsStore, useQuestionsStore } from "./store";
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
|
||||
export const setQuestions = (questions: RawQuestion[] | null) => setProducedState(state => {
|
||||
@ -76,20 +75,11 @@ export const addQuestionVariant = (questionId: string) => {
|
||||
case "variant":
|
||||
case "emoji":
|
||||
case "select":
|
||||
question.content.variants.push(createQuestionVariant());
|
||||
break;
|
||||
case "images":
|
||||
case "varimg":
|
||||
question.content.variants.push(createQuestionImageVariant());
|
||||
question.content.variants.push(createQuestionVariant());
|
||||
break;
|
||||
case "text":
|
||||
case "date":
|
||||
case "number":
|
||||
case "file":
|
||||
case "page":
|
||||
case "rating":
|
||||
throw new Error(`Cannot add variant to question of type "${question.type}"`);
|
||||
default: notReachable(question);
|
||||
default: throw new Error(`Cannot add variant to question of type "${question.type}"`);
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -173,7 +163,7 @@ export const setVariantImageUrl = (
|
||||
if (!("variants" in question.content)) return;
|
||||
|
||||
const variant = question.content.variants.find(variant => variant.id === variantId);
|
||||
if (!variant || !("originalImageUrl" in variant)) return;
|
||||
if (!variant) return;
|
||||
|
||||
if (variant.extendedText === url) return;
|
||||
|
||||
@ -192,8 +182,8 @@ export const setVariantOriginalImageUrl = (
|
||||
|
||||
const variant = question.content.variants.find(
|
||||
variant => variant.id === variantId
|
||||
) as ImageQuestionVariant | undefined;
|
||||
if (!variant || !("originalImageUrl" in variant)) return;
|
||||
) as QuestionVariant | undefined;
|
||||
if (!variant) return;
|
||||
|
||||
if (variant.originalImageUrl === url) return;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user