import { Box, Typography, useTheme } from "@mui/material"; import { useEffect, useState } from "react"; import { useDebouncedCallback } from "use-debounce"; import { CustomSlider } from "@ui_kit/CustomSlider"; import CustomTextField from "@ui_kit/CustomTextField"; import { useQuizViewStore } from "@stores/quizView"; import { sendAnswer } from "@api/quizRelase"; import { enqueueSnackbar } from "notistack"; import type { QuizQuestionNumber } from "@model/questionTypes/number"; import { useQuizData } from "@contexts/QuizDataContext"; import { quizThemes } from "@utils/themes/Publication/themePublication"; import type { ChangeEvent, SyntheticEvent } from "react"; type NumberProps = { currentQuestion: QuizQuestionNumber; }; export const Number = ({ currentQuestion }: NumberProps) => { const [isSending, setIsSending] = useState(false); const [inputValue, setInputValue] = useState("0"); const [minRange, setMinRange] = useState("0"); const [maxRange, setMaxRange] = useState("100000000000"); const [reversedInputValue, setReversedInputValue] = useState("0"); const [reversedMinRange, setReversedMinRange] = useState("0"); const [reversedMaxRange, setReversedMaxRange] = useState("100000000000"); const { settings, quizId, preview } = useQuizData(); const { updateAnswer } = useQuizViewStore((state) => state); const answers = useQuizViewStore((state) => state.answers); const theme = useTheme(); const [minBorder, maxBorder] = currentQuestion.content.range.split("—").map(window.Number); const min = minBorder < maxBorder ? minBorder : maxBorder; const max = minBorder < maxBorder ? maxBorder : minBorder; const reversed = minBorder > maxBorder; const answer = answers.find(({ questionId }) => questionId === currentQuestion.id)?.answer as string; const sliderValue = answer || (reversed ? max + min - currentQuestion.content.start + "—" + max : currentQuestion.content.start + "—" + max); useEffect(() => { console.log("reversed:", reversed); }, [reversed]); const sendAnswerToBackend = async (value: string, noUpdate = false) => { setIsSending(true); try { await sendAnswer({ questionId: currentQuestion.id, body: value, qid: quizId, preview, }); if (!noUpdate) { updateAnswer(currentQuestion.id, value, 0); } } catch (error) { enqueueSnackbar("ответ не был засчитан"); } setIsSending(false); }; const updateValueDebounced = useDebouncedCallback(async (value: string) => { if (reversed) { const newValue = window.Number(value) < window.Number(min) ? String(min) : window.Number(value) > window.Number(max) ? String(max) : value; setReversedInputValue(newValue); updateAnswer(currentQuestion.id, String(max + min - window.Number(newValue)), 0); await sendAnswerToBackend(String(window.Number(newValue)), true); return; } const newValue = window.Number(value) < window.Number(minRange) ? minRange : window.Number(value) > window.Number(maxRange) ? maxRange : value; setInputValue(newValue); await sendAnswerToBackend(newValue); }, 1000); const updateMinRangeDebounced = useDebouncedCallback(async (value: string, crowded = false) => { if (reversed) { const newMinRange = crowded ? window.Number(value.split("—")[1]) : max + min - window.Number(value.split("—")[0]) < min ? min : max + min - window.Number(value.split("—")[0]); const newMinValue = window.Number(value.split("—")[0]) > max ? String(max) : value.split("—")[0]; setReversedMinRange(crowded ? String(max + min - window.Number(newMinValue)) : newMinValue); updateAnswer(currentQuestion.id, `${newMinRange}—${value.split("—")[1]}`, 0); await sendAnswerToBackend(`${newMinValue}—${value.split("—")[1]}`, true); return; } const newMinValue = crowded ? maxRange : window.Number(value.split("—")[0]) < min ? String(min) : value.split("—")[0]; setMinRange(newMinValue); await sendAnswerToBackend(`${newMinValue}—${value.split("—")[1]}`); }, 1000); const updateMaxRangeDebounced = useDebouncedCallback(async (value: string, crowded = false) => { if (reversed) { const newMaxRange = crowded ? window.Number(value.split("—")[1]) : max + min - window.Number(value.split("—")[1]) > max ? max : max + min - window.Number(value.split("—")[1]); const newMaxValue = window.Number(value.split("—")[1]) < min ? String(min) : value.split("—")[1]; setReversedMaxRange(crowded ? String(max + min - window.Number(newMaxValue)) : newMaxValue); updateAnswer(currentQuestion.id, `${value.split("—")[0]}—${newMaxRange}`, 0); await sendAnswerToBackend(`${value.split("—")[0]}—${newMaxValue}`, true); return; } const newMaxValue = crowded ? minRange : window.Number(value.split("—")[1]) > max ? String(max) : value.split("—")[1]; setMaxRange(newMaxValue); await sendAnswerToBackend(`${value.split("—")[0]}—${newMaxValue}`); }, 1000); useEffect(() => { if (answer) { if (answer.includes("—")) { if (reversed) { setReversedMinRange(String(max + min - window.Number(answer.split("—")[0]))); setReversedMaxRange(String(max + min - window.Number(answer.split("—")[1]))); } else { setMinRange(answer.split("—")[0]); setMaxRange(answer.split("—")[1]); } } else { if (reversed) { setReversedInputValue(String(max + min - window.Number(answer))); } else { setInputValue(answer); } } } if (!answer) { setMinRange(String(currentQuestion.content.start)); setMaxRange(String(max)); if (currentQuestion.content.chooseRange) { setReversedMinRange(String(currentQuestion.content.start)); setReversedMaxRange(String(min)); } setReversedInputValue(String(currentQuestion.content.start)); setInputValue(String(currentQuestion.content.start)); } }, []); const onSliderChange = (_: Event, value: number | number[]) => { const range = Array.isArray(value) ? `${value[0]}—${value[1]}` : String(value); updateAnswer(currentQuestion.id, range, 0); }; const onChangeCommitted = async (_: Event | SyntheticEvent, value: number | number[]) => { if (currentQuestion.content.chooseRange && Array.isArray(value)) { if (reversed) { const newMinReversedValue = String(max + min - value[0]); const newMaxReversedValue = String(max + min - value[1]); setMinRange(String(value[0])); setMaxRange(String(value[1])); setReversedMinRange(newMinReversedValue); setReversedMaxRange(newMaxReversedValue); await sendAnswerToBackend(`${newMinReversedValue}—${newMaxReversedValue}`, true); return; } setMinRange(String(value[0])); setMaxRange(String(value[1])); await sendAnswerToBackend(`${value[0]}—${value[1]}`); return; } if (reversed) { setReversedInputValue(String(max + min - window.Number(value))); } else { setInputValue(String(value)); } await sendAnswerToBackend(String(value)); }; const changeValueLabelFormat = (value: number) => { if (!reversed) { return value; } const [minSliderBorder, maxSliderBorder] = sliderValue.split("—").map(window.Number); if (value === minSliderBorder) { return max + min - minSliderBorder; } return max + min - maxSliderBorder; }; const onInputChange = ({ target }: ChangeEvent) => { const value = target.value.replace(/\D/g, ""); if (reversed) { setReversedInputValue(value); } else { setInputValue(value); } updateValueDebounced(value); }; const onMinInputChange = ({ target }: ChangeEvent) => { const newValue = target.value.replace(/\D/g, ""); if (reversed) { setReversedMinRange(newValue); if (window.Number(newValue) <= window.Number(reversedMaxRange)) { const value = max + min - window.Number(reversedMaxRange); updateMinRangeDebounced(`${value}—${value}`, true); return; } updateMinRangeDebounced(`${newValue}—${max + min - window.Number(reversedMaxRange)}`); return; } setMinRange(newValue); if (window.Number(newValue) >= window.Number(maxRange)) { updateMinRangeDebounced(`${maxRange}—${maxRange}`, true); return; } updateMinRangeDebounced(`${newValue}—${maxRange}`); }; const onMaxInputChange = ({ target }: ChangeEvent) => { const newValue = target.value.replace(/\D/g, ""); if (reversed) { setReversedMaxRange(newValue); if (window.Number(newValue) >= window.Number(reversedMinRange)) { const value = max + min - window.Number(reversedMinRange); updateMaxRangeDebounced(`${value}—${value}`, true); return; } updateMaxRangeDebounced(`${max + min - window.Number(reversedMinRange)}—${newValue}`); return; } setMaxRange(newValue); if (window.Number(newValue) <= window.Number(minRange)) { updateMaxRangeDebounced(`${minRange}—${minRange}`, true); return; } updateMaxRangeDebounced(`${minRange}—${newValue}`); }; return ( {currentQuestion.title} 1 ? sliderValue.split("—").map((item) => window.Number(item)) : [min, min + 1] : window.Number(sliderValue.split("—")[0]) } min={min} max={max} step={currentQuestion.content.step || 1} onChange={onSliderChange} onChangeCommitted={onChangeCommitted} valueLabelFormat={changeValueLabelFormat} sx={{ color: theme.palette.primary.main, "& .MuiSlider-valueLabel": { background: theme.palette.primary.main, borderRadius: "8px", minWidth: "60px", height: "36px", }, }} /> {!currentQuestion.content.chooseRange && ( )} {currentQuestion.content.chooseRange && ( до )} ); };