Merge branch 'dev' into 'staging'
Dev See merge request frontend/squiz!337
This commit is contained in:
commit
40c029da34
@ -40,6 +40,7 @@
|
|||||||
"notistack": "^3.0.1",
|
"notistack": "^3.0.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
|
"react-colorful": "^5.6.1",
|
||||||
"react-cytoscapejs": "^2.0.0",
|
"react-cytoscapejs": "^2.0.0",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
"react-dnd-html5-backend": "^16.0.1",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
|
|||||||
@ -256,7 +256,7 @@ export const getIntegrationRules = async (
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
url: `${API_URL}/rules/${quizID}`,
|
url: `${API_URL}/rules/${quizID}`,
|
||||||
});
|
});
|
||||||
return [settingsResponse];
|
return [settingsResponse || null];
|
||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
const [error] = parseAxiosError(nativeError);
|
const [error] = parseAxiosError(nativeError);
|
||||||
return [null, `Не удалось получить настройки интеграции. ${error}`];
|
return [null, `Не удалось получить настройки интеграции. ${error}`];
|
||||||
@ -331,3 +331,18 @@ export const getCustomFields = async (
|
|||||||
return [null, `Не удалось получить список кастомных полей. ${error}`];
|
return [null, `Не удалось получить список кастомных полей. ${error}`];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Отвязать аккаунт амо от публикации
|
||||||
|
|
||||||
|
export const removeAmoAccount = async (): Promise<[void | null, string?]> => {
|
||||||
|
try {
|
||||||
|
await makeRequest<void>({
|
||||||
|
method: "DELETE",
|
||||||
|
url: `${API_URL}/delete`,
|
||||||
|
});
|
||||||
|
return [null, ""];
|
||||||
|
} catch (nativeError) {
|
||||||
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
return [null, `Не удалось отвязать аккаунт. ${error}`];
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -96,6 +96,10 @@ export type AnyTypedQuizQuestion =
|
|||||||
| QuizQuestionRating
|
| QuizQuestionRating
|
||||||
| QuizQuestionResult;
|
| QuizQuestionResult;
|
||||||
|
|
||||||
|
export type AllTypesQuestion =
|
||||||
|
| AnyTypedQuizQuestion
|
||||||
|
| UntypedQuizQuestion;
|
||||||
|
|
||||||
type FilterQuestionsWithVariants<T> = T extends {
|
type FilterQuestionsWithVariants<T> = T extends {
|
||||||
content: { variants: QuestionVariant[] };
|
content: { variants: QuestionVariant[] };
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { QuizQuestionBase, QuestionHint, PreviewRule } from "./shared";
|
import type { PreviewRule, QuestionHint, QuizQuestionBase } from "./shared";
|
||||||
|
|
||||||
export interface QuizQuestionText extends QuizQuestionBase {
|
export interface QuizQuestionText extends QuizQuestionBase {
|
||||||
type: "text";
|
type: "text";
|
||||||
@ -13,7 +13,7 @@ export interface QuizQuestionText extends QuizQuestionBase {
|
|||||||
required: boolean;
|
required: boolean;
|
||||||
/** Чекбокс "Автозаполнение адреса" */
|
/** Чекбокс "Автозаполнение адреса" */
|
||||||
autofill: boolean;
|
autofill: boolean;
|
||||||
answerType: "single" | "multi";
|
answerType: "single" | "multi" | "numberOnly";
|
||||||
hint: QuestionHint;
|
hint: QuestionHint;
|
||||||
rule: PreviewRule;
|
rule: PreviewRule;
|
||||||
back: string;
|
back: string;
|
||||||
|
|||||||
190
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/BannerWidgetSetup/BannerWidgetSetup.tsx
190
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/BannerWidgetSetup/BannerWidgetSetup.tsx
@ -37,21 +37,17 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
const [widgetWidth, setWidgetWidth] = useState<string>("");
|
const [widgetWidth, setWidgetWidth] = useState<string>("");
|
||||||
const [widgetHeight, setWidgetHeight] = useState<string>("");
|
const [widgetHeight, setWidgetHeight] = useState<string>("");
|
||||||
const [isAutoopenQuizSettingsOpen, setIsAutoopenQuizSettingsOpen] =
|
const [isAutoopenQuizSettingsOpen, setIsAutoopenQuizSettingsOpen] = useState<boolean>(false);
|
||||||
useState<boolean>(false);
|
|
||||||
const [hideOnMobile, setHideOnMobile] = useState<boolean>(false);
|
const [hideOnMobile, setHideOnMobile] = useState<boolean>(false);
|
||||||
const [rounded, setRounded] = useState<boolean>(false);
|
const [rounded, setRounded] = useState<boolean>(false);
|
||||||
const [withShadow, setWithShadow] = useState<boolean>(false);
|
const [withShadow, setWithShadow] = useState<boolean>(false);
|
||||||
const [buttonFlash, setButtonFlash] = useState<boolean>(false);
|
const [buttonFlash, setButtonFlash] = useState<boolean>(false);
|
||||||
const [buttonBackgroundColor, setButtonBackgroundColor] = useState<string>(
|
const [buttonBackgroundColor, setButtonBackgroundColor] = useState<string>(theme.palette.brightPurple.main);
|
||||||
theme.palette.brightPurple.main,
|
|
||||||
);
|
|
||||||
const [buttonTextColor, setButtonTextColor] = useState<string>("#FFFFFF");
|
const [buttonTextColor, setButtonTextColor] = useState<string>("#FFFFFF");
|
||||||
const [autoShowQuiz, setAutoShowQuiz] = useState<boolean>(false);
|
const [autoShowQuiz, setAutoShowQuiz] = useState<boolean>(false);
|
||||||
const [autoShowQuizTime, setAutoShowQuizTime] = useState<number>(10);
|
const [autoShowQuizTime, setAutoShowQuizTime] = useState<number>(10);
|
||||||
const [openOnLeaveAttempt, setOpenOnLeaveAttempt] = useState<boolean>(false);
|
const [openOnLeaveAttempt, setOpenOnLeaveAttempt] = useState<boolean>(false);
|
||||||
const [position, setPosition] =
|
const [position, setPosition] = useState<BannerWidgetParams["position"]>("bottomleft");
|
||||||
useState<BannerWidgetParams["position"]>("bottomleft");
|
|
||||||
const [bannerFullWidth, setBannerFullWidth] = useState<boolean>(false);
|
const [bannerFullWidth, setBannerFullWidth] = useState<boolean>(false);
|
||||||
const [autoShowWidgetTime, setAutoShowWidgetTime] = useState<number>(10);
|
const [autoShowWidgetTime, setAutoShowWidgetTime] = useState<number>(10);
|
||||||
const [appealText, setAppealText] = useState<string>("");
|
const [appealText, setAppealText] = useState<string>("");
|
||||||
@ -88,12 +84,7 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
: undefined,
|
: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return <WidgetScript scriptText={scriptText} helperText="Установите код внутрь тэга head" />;
|
||||||
<WidgetScript
|
|
||||||
scriptText={scriptText}
|
|
||||||
helperText="Установите код внутрь тэга head"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -129,17 +120,39 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
sx={[
|
sx={[
|
||||||
{
|
{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: "calc(12.5 / 262 * 100%)",
|
|
||||||
left: "calc(50.6 / 520 * 100%)",
|
|
||||||
width: "calc(196 / 520 * 100%)",
|
width: "calc(196 / 520 * 100%)",
|
||||||
height: "calc(30 / 262 * 100%)",
|
height: "calc(30 / 262 * 100%)",
|
||||||
},
|
},
|
||||||
bannerFullWidth && {
|
position === "topleft" && {
|
||||||
top: "calc(7 / 262 * 100%)",
|
top: "calc(12.5 / 262 * 100%)",
|
||||||
left: "calc(45 / 520 * 100%)",
|
left: "calc(50.6 / 520 * 100%)",
|
||||||
width: "calc(348 / 520 * 100%)",
|
|
||||||
height: "calc(30 / 262 * 100%)",
|
|
||||||
},
|
},
|
||||||
|
position === "topright" && {
|
||||||
|
top: "calc(12.5 / 262 * 100%)",
|
||||||
|
left: "calc(190 / 520 * 100%)",
|
||||||
|
},
|
||||||
|
position === "bottomleft" && {
|
||||||
|
top: "calc(178 / 262 * 100%)",
|
||||||
|
left: "calc(50.6 / 520 * 100%)",
|
||||||
|
},
|
||||||
|
position === "bottomright" && {
|
||||||
|
top: "calc(178 / 262 * 100%)",
|
||||||
|
left: "calc(190 / 520 * 100%)",
|
||||||
|
},
|
||||||
|
bannerFullWidth &&
|
||||||
|
position.startsWith("top") && {
|
||||||
|
top: "calc(7 / 262 * 100%)",
|
||||||
|
left: "calc(45 / 520 * 100%)",
|
||||||
|
width: "calc(348 / 520 * 100%)",
|
||||||
|
height: "calc(30 / 262 * 100%)",
|
||||||
|
},
|
||||||
|
bannerFullWidth &&
|
||||||
|
position.startsWith("bottom") && {
|
||||||
|
top: "calc(185 / 262 * 100%)",
|
||||||
|
left: "calc(45 / 520 * 100%)",
|
||||||
|
width: "calc(348 / 520 * 100%)",
|
||||||
|
height: "calc(30 / 262 * 100%)",
|
||||||
|
},
|
||||||
pulsation && {
|
pulsation && {
|
||||||
":before": {
|
":before": {
|
||||||
content: "''",
|
content: "''",
|
||||||
@ -196,16 +209,10 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
color: "white",
|
color: "white",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography fontSize="calc(6 / 29.5 * 100cqh)" lineHeight="120%">
|
||||||
fontSize="calc(6 / 29.5 * 100cqh)"
|
|
||||||
lineHeight="120%"
|
|
||||||
>
|
|
||||||
{appealText || "Пройти тест"}
|
{appealText || "Пройти тест"}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography
|
<Typography fontSize="calc(11 / 29.5 * 100cqh)" lineHeight="120%">
|
||||||
fontSize="calc(11 / 29.5 * 100cqh)"
|
|
||||||
lineHeight="120%"
|
|
||||||
>
|
|
||||||
{quizHeaderText || "Заголовок теста"}
|
{quizHeaderText || "Заголовок теста"}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
@ -220,8 +227,7 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
height: "calc(10 / 29.5 * 100%)",
|
height: "calc(10 / 29.5 * 100%)",
|
||||||
width: "auto",
|
width: "auto",
|
||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
||||||
backgroundColor:
|
backgroundColor: rounded || bannerFullWidth ? "#581CA7" : undefined,
|
||||||
rounded || bannerFullWidth ? "#581CA7" : undefined,
|
|
||||||
borderRadius: "50%",
|
borderRadius: "50%",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -255,9 +261,7 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
gap: "20px",
|
gap: "20px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
<Typography sx={{ color: theme.palette.grey2.main }}>Ширина окна (px)</Typography>
|
||||||
Ширина окна (px)
|
|
||||||
</Typography>
|
|
||||||
<PenaTextField
|
<PenaTextField
|
||||||
type="number"
|
type="number"
|
||||||
value={widgetWidth}
|
value={widgetWidth}
|
||||||
@ -273,9 +277,7 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
gap: "20px",
|
gap: "20px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
<Typography sx={{ color: theme.palette.grey2.main }}>Высота окна (px)</Typography>
|
||||||
Высота окна (px)
|
|
||||||
</Typography>
|
|
||||||
<PenaTextField
|
<PenaTextField
|
||||||
type="number"
|
type="number"
|
||||||
value={widgetHeight}
|
value={widgetHeight}
|
||||||
@ -286,18 +288,14 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
<Typography sx={{ color: theme.palette.grey2.main }}>Текст-призыв</Typography>
|
||||||
Текст-призыв
|
|
||||||
</Typography>
|
|
||||||
<PenaTextField
|
<PenaTextField
|
||||||
placeholder="Пройти тест"
|
placeholder="Пройти тест"
|
||||||
value={appealText}
|
value={appealText}
|
||||||
onChange={(e) => setAppealText(e.target.value)}
|
onChange={(e) => setAppealText(e.target.value)}
|
||||||
FormControlSx={{ maxWidth: "360px" }}
|
FormControlSx={{ maxWidth: "360px" }}
|
||||||
/>
|
/>
|
||||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
<Typography sx={{ color: theme.palette.grey2.main }}>Заголовок quiz</Typography>
|
||||||
Заголовок quiz
|
|
||||||
</Typography>
|
|
||||||
<PenaTextField
|
<PenaTextField
|
||||||
placeholder="Заголовок quiz"
|
placeholder="Заголовок quiz"
|
||||||
value={quizHeaderText}
|
value={quizHeaderText}
|
||||||
@ -311,9 +309,7 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
<Typography sx={{ color: theme.palette.grey2.main }}>Показывать через</Typography>
|
||||||
Показывать через
|
|
||||||
</Typography>
|
|
||||||
<PenaTextField
|
<PenaTextField
|
||||||
type="number"
|
type="number"
|
||||||
value={autoShowWidgetTime}
|
value={autoShowWidgetTime}
|
||||||
@ -322,9 +318,7 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
width: "90px",
|
width: "90px",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
<Typography sx={{ color: theme.palette.grey2.main }}>секунд</Typography>
|
||||||
секунд
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -333,20 +327,10 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
<Typography sx={{ color: theme.palette.grey2.main }}>Цвет кнопки</Typography>
|
||||||
Цвет кнопки
|
<CircleColorPicker color={buttonBackgroundColor} onChange={(color) => setButtonBackgroundColor(color)} />
|
||||||
</Typography>
|
<Typography sx={{ color: theme.palette.grey2.main }}>Цвет текста кнопки</Typography>
|
||||||
<CircleColorPicker
|
<CircleColorPicker color={buttonTextColor} onChange={(color) => setButtonTextColor(color)} />
|
||||||
color={buttonBackgroundColor}
|
|
||||||
onChange={(color) => setButtonBackgroundColor(color)}
|
|
||||||
/>
|
|
||||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
|
||||||
Цвет текста кнопки
|
|
||||||
</Typography>
|
|
||||||
<CircleColorPicker
|
|
||||||
color={buttonTextColor}
|
|
||||||
onChange={(color) => setButtonTextColor(color)}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
<CustomCheckbox
|
<CustomCheckbox
|
||||||
label="Баннер на всю ширину экрана"
|
label="Баннер на всю ширину экрана"
|
||||||
@ -356,9 +340,7 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
if (e.target.checked) setPosition("topleft");
|
if (e.target.checked) setPosition("topleft");
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
<Typography sx={{ color: theme.palette.grey2.main }}>Расположение</Typography>
|
||||||
Расположение
|
|
||||||
</Typography>
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
value={position}
|
value={position}
|
||||||
@ -384,17 +366,13 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
label="Сверху страницы"
|
label="Сверху страницы"
|
||||||
value="topleft"
|
value="topleft"
|
||||||
control={
|
control={<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />}
|
||||||
<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />
|
|
||||||
}
|
|
||||||
sx={{ color: theme.palette.grey2.main }}
|
sx={{ color: theme.palette.grey2.main }}
|
||||||
/>
|
/>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
label="Снизу страницы"
|
label="Снизу страницы"
|
||||||
value="bottomleft"
|
value="bottomleft"
|
||||||
control={
|
control={<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />}
|
||||||
<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />
|
|
||||||
}
|
|
||||||
sx={{ color: theme.palette.grey2.main }}
|
sx={{ color: theme.palette.grey2.main }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@ -409,23 +387,13 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
label="Слева сверху"
|
label="Слева сверху"
|
||||||
value="topleft"
|
value="topleft"
|
||||||
control={
|
control={<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />}
|
||||||
<Radio
|
|
||||||
checkedIcon={<RadioCheck />}
|
|
||||||
icon={<RadioIcon />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
sx={{ color: theme.palette.grey2.main }}
|
sx={{ color: theme.palette.grey2.main }}
|
||||||
/>
|
/>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
label="Справа сверху"
|
label="Слева снизу"
|
||||||
value="topright"
|
value="bottomleft"
|
||||||
control={
|
control={<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />}
|
||||||
<Radio
|
|
||||||
checkedIcon={<RadioCheck />}
|
|
||||||
icon={<RadioIcon />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
sx={{ color: theme.palette.grey2.main }}
|
sx={{ color: theme.palette.grey2.main }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@ -436,25 +404,15 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
label="Слева снизу"
|
label="Справа сверху"
|
||||||
value="bottomleft"
|
value="topright"
|
||||||
control={
|
control={<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />}
|
||||||
<Radio
|
|
||||||
checkedIcon={<RadioCheck />}
|
|
||||||
icon={<RadioIcon />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
sx={{ color: theme.palette.grey2.main }}
|
sx={{ color: theme.palette.grey2.main }}
|
||||||
/>
|
/>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
label="Справа снизу"
|
label="Справа снизу"
|
||||||
value="bottomright"
|
value="bottomright"
|
||||||
control={
|
control={<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />}
|
||||||
<Radio
|
|
||||||
checkedIcon={<RadioCheck />}
|
|
||||||
icon={<RadioIcon />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
sx={{ color: theme.palette.grey2.main }}
|
sx={{ color: theme.palette.grey2.main }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@ -462,26 +420,12 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
)}
|
)}
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
<Typography sx={{ color: theme.palette.grey2.main }}>Параметры</Typography>
|
||||||
Параметры
|
|
||||||
</Typography>
|
|
||||||
{!bannerFullWidth && (
|
{!bannerFullWidth && (
|
||||||
<CustomCheckbox
|
<CustomCheckbox label="Закругленная" checked={rounded} handleChange={(e) => setRounded(e.target.checked)} />
|
||||||
label="Закругленная"
|
|
||||||
checked={rounded}
|
|
||||||
handleChange={(e) => setRounded(e.target.checked)}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
<CustomCheckbox
|
<CustomCheckbox label="С тенью" checked={withShadow} handleChange={(e) => setWithShadow(e.target.checked)} />
|
||||||
label="С тенью"
|
<CustomCheckbox label="С бликом" checked={buttonFlash} handleChange={(e) => setButtonFlash(e.target.checked)} />
|
||||||
checked={withShadow}
|
|
||||||
handleChange={(e) => setWithShadow(e.target.checked)}
|
|
||||||
/>
|
|
||||||
<CustomCheckbox
|
|
||||||
label="С бликом"
|
|
||||||
checked={buttonFlash}
|
|
||||||
handleChange={(e) => setButtonFlash(e.target.checked)}
|
|
||||||
/>
|
|
||||||
<CustomCheckbox
|
<CustomCheckbox
|
||||||
label={'Эффект "пульсация"'}
|
label={'Эффект "пульсация"'}
|
||||||
checked={pulsation}
|
checked={pulsation}
|
||||||
@ -546,22 +490,16 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
<Typography sx={{ color: theme.palette.grey2.main }}>Показывать через</Typography>
|
||||||
Показывать через
|
|
||||||
</Typography>
|
|
||||||
<PenaTextField
|
<PenaTextField
|
||||||
type="number"
|
type="number"
|
||||||
value={autoShowQuizTime}
|
value={autoShowQuizTime}
|
||||||
onChange={(e) =>
|
onChange={(e) => setAutoShowQuizTime(parseInt(e.target.value))}
|
||||||
setAutoShowQuizTime(parseInt(e.target.value))
|
|
||||||
}
|
|
||||||
FormControlSx={{
|
FormControlSx={{
|
||||||
width: "90px",
|
width: "90px",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
<Typography sx={{ color: theme.palette.grey2.main }}>секунд</Typography>
|
||||||
секунд
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|||||||
@ -8,24 +8,29 @@ import {
|
|||||||
import React, { FC, useEffect, useMemo, useState } from "react";
|
import React, { FC, useEffect, useMemo, useState } from "react";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
import { AmoRemoveAccount } from "./AmoRemoveAccount/AmoRemoveAccount";
|
||||||
import { AmoLogin } from "./AmoLogin/AmoLogin";
|
import { AmoLogin } from "./AmoLogin/AmoLogin";
|
||||||
import { AmoStep2 } from "./AmoStep2/AmoStep2";
|
import { AmoStep2 } from "./AmoStep2/AmoStep2";
|
||||||
import { AmoStep3 } from "./AmoStep3/AmoStep3";
|
import { AmoStep3 } from "./AmoStep3/AmoStep3";
|
||||||
import { AmoStep4 } from "./AmoStep4/AmoStep4";
|
import { AmoStep4 } from "./AmoStep4/AmoStep4";
|
||||||
import { AmoStep6 } from "./IntegrationStep6/AmoStep6";
|
import { AmoStep6 } from "./IntegrationStep6/AmoStep6";
|
||||||
|
import { AmoStep7 } from "./IntegrationStep7/AmoStep7";
|
||||||
import { AmoModalTitle } from "./AmoModalTitle/AmoModalTitle";
|
import { AmoModalTitle } from "./AmoModalTitle/AmoModalTitle";
|
||||||
import { AmoSettingsBlock } from "./SettingsBlock/AmoSettingsBlock";
|
import { AmoSettingsBlock } from "./SettingsBlock/AmoSettingsBlock";
|
||||||
import { AmoStep7 } from "./IntegrationStep7/AmoStep7";
|
|
||||||
import { AmoAccountInfo } from "./AmoAccountInfo/AmoAccountInfo";
|
import { AmoAccountInfo } from "./AmoAccountInfo/AmoAccountInfo";
|
||||||
import { AccountResponse, getAccount } from "@api/integration";
|
import { AccountResponse, IntegrationRules, getAccount, getIntegrationRules } from "@api/integration";
|
||||||
|
import { useQuestions } from "@/stores/questions/hooks";
|
||||||
|
import { redirect } from "react-router-dom";
|
||||||
|
import { enqueueSnackbar } from "notistack";
|
||||||
|
|
||||||
export type TitleKeys = "contacts" | "company" | "deal" | "users" | "buyers";
|
export type TitleKeys = "contacts" | "company" | "deal" | "buyers";
|
||||||
|
|
||||||
export type TQuestionEntity = Record<TitleKeys, string[] | []>;
|
export type TQuestionEntity = Record<TitleKeys, string[] | []>;
|
||||||
type IntegrationsModalProps = {
|
type IntegrationsModalProps = {
|
||||||
isModalOpen: boolean;
|
isModalOpen: boolean;
|
||||||
handleCloseModal: () => void;
|
handleCloseModal: () => void;
|
||||||
companyName: string | null;
|
companyName: string | null;
|
||||||
|
quizID: number | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TagKeys = "contact" | "company" | "deal" | "buyer";
|
export type TagKeys = "contact" | "company" | "deal" | "buyer";
|
||||||
@ -35,15 +40,20 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
|
|||||||
isModalOpen,
|
isModalOpen,
|
||||||
handleCloseModal,
|
handleCloseModal,
|
||||||
companyName,
|
companyName,
|
||||||
|
quizID,
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||||
|
|
||||||
|
const { questions } = useQuestions();
|
||||||
|
|
||||||
const [step, setStep] = useState<number>(0);
|
const [step, setStep] = useState<number>(0);
|
||||||
const [isSettingsBlock, setIsSettingsBlock] = useState<boolean>(false);
|
const [isSettingsBlock, setIsSettingsBlock] = useState<boolean>(false);
|
||||||
|
const [isRemoveAccount, setIsRemoveAccount] = useState<boolean>(false);
|
||||||
|
|
||||||
const [accountInfo, setAccountInfo] = useState<AccountResponse | null>(null);
|
const [accountInfo, setAccountInfo] = useState<AccountResponse | null>(null);
|
||||||
|
const [integrationRules, setIntegrationRules] = useState<IntegrationRules | null>(null);
|
||||||
const [selectedPipelinePerformer, setSelectedPipelinePerformer] = useState<
|
const [selectedPipelinePerformer, setSelectedPipelinePerformer] = useState<
|
||||||
string | null
|
string | null
|
||||||
>(null);
|
>(null);
|
||||||
@ -56,10 +66,9 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
|
|||||||
string | null
|
string | null
|
||||||
>(null);
|
>(null);
|
||||||
const [questionEntity, setQuestionEntity] = useState<TQuestionEntity>({
|
const [questionEntity, setQuestionEntity] = useState<TQuestionEntity>({
|
||||||
|
deal: [],
|
||||||
contacts: [],
|
contacts: [],
|
||||||
company: [],
|
company: [],
|
||||||
deal: [],
|
|
||||||
users: [],
|
|
||||||
buyers: [],
|
buyers: [],
|
||||||
});
|
});
|
||||||
const [tags, setTags] = useState<TTags>({
|
const [tags, setTags] = useState<TTags>({
|
||||||
@ -68,21 +77,38 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
|
|||||||
company: [],
|
company: [],
|
||||||
buyer: [],
|
buyer: [],
|
||||||
});
|
});
|
||||||
console.log(accountInfo)
|
console.log(questionEntity)
|
||||||
|
console.log(tags)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isModalOpen) {
|
if (isModalOpen && quizID !== undefined && !isRemoveAccount) {
|
||||||
const fetchAccount = async () => {
|
const fetchAccount = async () => {
|
||||||
const [account, error] = await getAccount();
|
const [account, error] = await getAccount();
|
||||||
if (account && !error) {
|
|
||||||
setAccountInfo(account);
|
if (error) {
|
||||||
} else {
|
enqueueSnackbar(error)
|
||||||
setAccountInfo(null);
|
setAccountInfo(null);
|
||||||
}
|
}
|
||||||
|
if (account) {
|
||||||
|
setAccountInfo(account);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
const fetchRules = async () => {
|
||||||
|
const [settingsResponse, error] = await getIntegrationRules(quizID.toString());
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
enqueueSnackbar(error)
|
||||||
|
setIntegrationRules(null);
|
||||||
|
}
|
||||||
|
if (settingsResponse) {
|
||||||
|
setIntegrationRules(settingsResponse);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
fetchAccount();
|
fetchAccount();
|
||||||
|
fetchRules();
|
||||||
}
|
}
|
||||||
}, [isModalOpen]);
|
}, [isModalOpen, isRemoveAccount]);
|
||||||
|
|
||||||
const handleNextStep = () => {
|
const handleNextStep = () => {
|
||||||
setStep((prevState) => prevState + 1);
|
setStep((prevState) => prevState + 1);
|
||||||
@ -152,26 +178,27 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Соотнесение вопросов и сущностей",
|
title: "Добавление тегов",
|
||||||
isSettingsAvailable: true,
|
isSettingsAvailable: true,
|
||||||
component: (
|
component: (
|
||||||
<AmoStep6
|
<AmoStep6
|
||||||
questionEntity={questionEntity}
|
tags={tags}
|
||||||
setQuestionEntity={setQuestionEntity}
|
|
||||||
handlePrevStep={handlePrevStep}
|
handlePrevStep={handlePrevStep}
|
||||||
handleNextStep={handleNextStep}
|
handleNextStep={handleNextStep}
|
||||||
|
setTags={setTags}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Добавление тегов",
|
title: "Соотнесение вопросов и сущностей",
|
||||||
isSettingsAvailable: true,
|
isSettingsAvailable: true,
|
||||||
component: (
|
component: (
|
||||||
<AmoStep7
|
<AmoStep7
|
||||||
handleSmallBtn={handlePrevStep}
|
questionEntity={questionEntity}
|
||||||
handleLargeBtn={handleSave}
|
setQuestionEntity={setQuestionEntity}
|
||||||
tags={tags}
|
handlePrevStep={handlePrevStep}
|
||||||
setTags={setTags}
|
handleNextStep={handleSave}
|
||||||
|
questions={questions}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -190,6 +217,9 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
|
|||||||
|
|
||||||
const stepTitles = steps.map((step) => step.title);
|
const stepTitles = steps.map((step) => step.title);
|
||||||
|
|
||||||
|
//Если нет контекста квиза, то и делать на этой страничке нечего
|
||||||
|
if (quizID === undefined) redirect("/list")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={isModalOpen}
|
open={isModalOpen}
|
||||||
@ -252,8 +282,14 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
|
|||||||
isSettingsBlock={isSettingsBlock}
|
isSettingsBlock={isSettingsBlock}
|
||||||
setIsSettingsBlock={setIsSettingsBlock}
|
setIsSettingsBlock={setIsSettingsBlock}
|
||||||
setStep={setStep}
|
setStep={setStep}
|
||||||
|
startRemoveAccount={() => setIsRemoveAccount(true)}
|
||||||
/>
|
/>
|
||||||
{isSettingsBlock ? (
|
{isRemoveAccount && (
|
||||||
|
<AmoRemoveAccount
|
||||||
|
stopThisPage={() => setIsRemoveAccount(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{isSettingsBlock && (
|
||||||
<Box sx={{ flexGrow: 1, width: "100%" }}>
|
<Box sx={{ flexGrow: 1, width: "100%" }}>
|
||||||
<AmoSettingsBlock
|
<AmoSettingsBlock
|
||||||
stepTitles={stepTitles}
|
stepTitles={stepTitles}
|
||||||
@ -268,7 +304,8 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
|
|||||||
tags={tags}
|
tags={tags}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
)}
|
||||||
|
{!isSettingsBlock && !isRemoveAccount && (
|
||||||
<Box sx={{ flexGrow: 1, width: "100%" }}>{steps[step].component}</Box>
|
<Box sx={{ flexGrow: 1, width: "100%" }}>{steps[step].component}</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@ -10,6 +10,7 @@ type AmoModalTitleProps = {
|
|||||||
isSettingsBlock?: boolean;
|
isSettingsBlock?: boolean;
|
||||||
setIsSettingsBlock: (value: boolean) => void;
|
setIsSettingsBlock: (value: boolean) => void;
|
||||||
setStep: (value: number) => void;
|
setStep: (value: number) => void;
|
||||||
|
startRemoveAccount: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AmoModalTitle: FC<AmoModalTitleProps> = ({
|
export const AmoModalTitle: FC<AmoModalTitleProps> = ({
|
||||||
@ -18,13 +19,16 @@ export const AmoModalTitle: FC<AmoModalTitleProps> = ({
|
|||||||
setIsSettingsBlock,
|
setIsSettingsBlock,
|
||||||
isSettingsBlock,
|
isSettingsBlock,
|
||||||
setStep,
|
setStep,
|
||||||
|
startRemoveAccount
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
console.log(isSettingsBlock)
|
||||||
|
const handleClick = useCallback(async () => {
|
||||||
if (isSettingsBlock) {
|
if (isSettingsBlock) {
|
||||||
setIsSettingsBlock(false);
|
startRemoveAccount();
|
||||||
|
setIsSettingsBlock(false)
|
||||||
setStep(0);
|
setStep(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,61 @@
|
|||||||
|
import { FC } from "react"
|
||||||
|
import { Button, Typography, useTheme, Box } from "@mui/material"
|
||||||
|
import { removeAmoAccount } from "@/api/integration";
|
||||||
|
import { enqueueSnackbar } from "notistack";
|
||||||
|
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
stopThisPage: () => void;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AmoRemoveAccount: FC<Props> = ({
|
||||||
|
stopThisPage,
|
||||||
|
|
||||||
|
}: Props) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const removeAccount = async () => {
|
||||||
|
const [, error] = await removeAmoAccount()
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
enqueueSnackbar(error)
|
||||||
|
} else {
|
||||||
|
stopThisPage()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
mt: "30px"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography textAlign="center">
|
||||||
|
Вы хотите сменить аккаунт?
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-evenly",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
margin: "30px auto",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
width: "150px",
|
||||||
|
}}
|
||||||
|
onClick={stopThisPage}
|
||||||
|
>отмена</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
width: "150px",
|
||||||
|
}}
|
||||||
|
onClick={removeAccount}
|
||||||
|
>сменить</Button>
|
||||||
|
</Box>
|
||||||
|
</Box >
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -7,23 +7,24 @@ import {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { ItemsSelectionView } from "./ItemsSelectionView/ItemsSelectionView";
|
|
||||||
import { ItemDetailsView } from "./ItemDetailsView/ItemDetailsView";
|
|
||||||
import { TitleKeys, TQuestionEntity } from "../AmoCRMModal";
|
|
||||||
import Box from "@mui/material/Box";
|
|
||||||
|
|
||||||
type AmoStep6Props = {
|
import { TagKeys, TTags } from "../AmoCRMModal";
|
||||||
handlePrevStep: () => void;
|
import Box from "@mui/material/Box";
|
||||||
|
import { ItemsSelectionView } from "../IntegrationStep7/ItemsSelectionView/ItemsSelectionView";
|
||||||
|
import { TagsDetailsView } from "./TagsDetailsView/TagsDetailsView";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
handleNextStep: () => void;
|
handleNextStep: () => void;
|
||||||
questionEntity: TQuestionEntity;
|
handlePrevStep: () => void;
|
||||||
setQuestionEntity: Dispatch<SetStateAction<TQuestionEntity>>;
|
tags: TTags;
|
||||||
|
setTags: Dispatch<SetStateAction<TTags>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AmoStep6: FC<AmoStep6Props> = ({
|
export const AmoStep6: FC<Props> = ({
|
||||||
handlePrevStep,
|
|
||||||
handleNextStep,
|
handleNextStep,
|
||||||
questionEntity,
|
handlePrevStep,
|
||||||
setQuestionEntity,
|
tags,
|
||||||
|
setTags,
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [isSelection, setIsSelection] = useState<boolean>(false);
|
const [isSelection, setIsSelection] = useState<boolean>(false);
|
||||||
@ -33,14 +34,14 @@ export const AmoStep6: FC<AmoStep6Props> = ({
|
|||||||
const handleAdd = useCallback(() => {
|
const handleAdd = useCallback(() => {
|
||||||
if (!activeItem || !selectedValue) return;
|
if (!activeItem || !selectedValue) return;
|
||||||
|
|
||||||
setQuestionEntity((prevState) => ({
|
setTags((prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
[activeItem]: [...prevState[activeItem as TitleKeys], selectedValue],
|
[activeItem]: [...prevState[activeItem as TagKeys], selectedValue],
|
||||||
}));
|
}));
|
||||||
}, [activeItem, setQuestionEntity, selectedValue]);
|
}, [activeItem, setTags, selectedValue]);
|
||||||
|
|
||||||
const items = useMemo(
|
const items = useMemo(
|
||||||
() => ["Город", "Имя", "Фамилия", "Отчество", "Контрагент"],
|
() => ["#тег с результатом 1", "#еще один тег с результатом 2", "#тег"],
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -58,6 +59,7 @@ export const AmoStep6: FC<AmoStep6Props> = ({
|
|||||||
items={items}
|
items={items}
|
||||||
selectedValue={selectedValue}
|
selectedValue={selectedValue}
|
||||||
setSelectedValue={setSelectedValue}
|
setSelectedValue={setSelectedValue}
|
||||||
|
type={"typeTags"}
|
||||||
onSmallBtnClick={() => {
|
onSmallBtnClick={() => {
|
||||||
setActiveItem(null);
|
setActiveItem(null);
|
||||||
setIsSelection(false);
|
setIsSelection(false);
|
||||||
@ -69,11 +71,11 @@ export const AmoStep6: FC<AmoStep6Props> = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ItemDetailsView
|
<TagsDetailsView
|
||||||
setIsSelection={setIsSelection}
|
setIsSelection={setIsSelection}
|
||||||
handleNextStep={handleNextStep}
|
|
||||||
handlePrevStep={handlePrevStep}
|
handlePrevStep={handlePrevStep}
|
||||||
questionEntity={questionEntity}
|
handleNextStep={handleNextStep}
|
||||||
|
tags={tags}
|
||||||
setActiveItem={setActiveItem}
|
setActiveItem={setActiveItem}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -2,19 +2,19 @@ import { Box, Typography, useTheme } from "@mui/material";
|
|||||||
import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock";
|
import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock";
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { TagKeys, TTags } from "../../AmoCRMModal";
|
import { TagKeys, TTags } from "../../AmoCRMModal";
|
||||||
import { Item } from "../../IntegrationStep6/Item/Item";
|
import { Item } from "../../IntegrationStep7/Item/Item";
|
||||||
|
|
||||||
type TagsDetailsViewProps = {
|
type TagsDetailsViewProps = {
|
||||||
setIsSelection: (value: boolean) => void;
|
setIsSelection: (value: boolean) => void;
|
||||||
handleSmallBtn: () => void;
|
handlePrevStep: () => void;
|
||||||
handleLargeBtn: () => void;
|
handleNextStep: () => void;
|
||||||
tags: TTags;
|
tags: TTags;
|
||||||
setActiveItem: (value: string | null) => void;
|
setActiveItem: (value: string | null) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TagsDetailsView: FC<TagsDetailsViewProps> = ({
|
export const TagsDetailsView: FC<TagsDetailsViewProps> = ({
|
||||||
handleSmallBtn,
|
handlePrevStep,
|
||||||
handleLargeBtn,
|
handleNextStep,
|
||||||
tags,
|
tags,
|
||||||
setActiveItem,
|
setActiveItem,
|
||||||
setIsSelection,
|
setIsSelection,
|
||||||
@ -89,9 +89,8 @@ export const TagsDetailsView: FC<TagsDetailsViewProps> = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StepButtonsBlock
|
<StepButtonsBlock
|
||||||
onSmallBtnClick={handleSmallBtn}
|
onSmallBtnClick={handlePrevStep}
|
||||||
onLargeBtnClick={handleLargeBtn}
|
onLargeBtnClick={handleNextStep}
|
||||||
largeBtnText={"Сохранить"}
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
@ -7,24 +7,26 @@ import {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
import { ItemsSelectionView } from "./ItemsSelectionView/ItemsSelectionView";
|
||||||
import { TagKeys, TTags } from "../AmoCRMModal";
|
import { ItemDetailsView } from "./ItemDetailsView/ItemDetailsView";
|
||||||
|
import { TitleKeys, TQuestionEntity } from "../AmoCRMModal";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import { ItemsSelectionView } from "../IntegrationStep6/ItemsSelectionView/ItemsSelectionView";
|
import type { AllTypesQuestion } from "@model/questionTypes/shared"
|
||||||
import { TagsDetailsView } from "./TagsDetailsView/TagsDetailsView";
|
|
||||||
|
|
||||||
type AmoStep7Props = {
|
type Props = {
|
||||||
handleSmallBtn: () => void;
|
handlePrevStep: () => void;
|
||||||
handleLargeBtn: () => void;
|
handleNextStep: () => void;
|
||||||
tags: TTags;
|
questionEntity: TQuestionEntity;
|
||||||
setTags: Dispatch<SetStateAction<TTags>>;
|
setQuestionEntity: Dispatch<SetStateAction<TQuestionEntity>>;
|
||||||
|
questions: AllTypesQuestion[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AmoStep7: FC<AmoStep7Props> = ({
|
export const AmoStep7: FC<Props> = ({
|
||||||
handleSmallBtn,
|
handlePrevStep,
|
||||||
handleLargeBtn,
|
handleNextStep,
|
||||||
tags,
|
questionEntity,
|
||||||
setTags,
|
setQuestionEntity,
|
||||||
|
questions,
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [isSelection, setIsSelection] = useState<boolean>(false);
|
const [isSelection, setIsSelection] = useState<boolean>(false);
|
||||||
@ -34,14 +36,14 @@ export const AmoStep7: FC<AmoStep7Props> = ({
|
|||||||
const handleAdd = useCallback(() => {
|
const handleAdd = useCallback(() => {
|
||||||
if (!activeItem || !selectedValue) return;
|
if (!activeItem || !selectedValue) return;
|
||||||
|
|
||||||
setTags((prevState) => ({
|
setQuestionEntity((prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
[activeItem]: [...prevState[activeItem as TagKeys], selectedValue],
|
[activeItem]: [...prevState[activeItem as TitleKeys], selectedValue],
|
||||||
}));
|
}));
|
||||||
}, [activeItem, setTags, selectedValue]);
|
}, [activeItem, setQuestionEntity, selectedValue]);
|
||||||
|
|
||||||
const items = useMemo(
|
const items = useMemo(
|
||||||
() => ["#тег с результатом 1", "#еще один тег с результатом 2", "#тег"],
|
() => ["Город", "Имя", "Фамилия", "Отчество", "Контрагент"],
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -59,7 +61,6 @@ export const AmoStep7: FC<AmoStep7Props> = ({
|
|||||||
items={items}
|
items={items}
|
||||||
selectedValue={selectedValue}
|
selectedValue={selectedValue}
|
||||||
setSelectedValue={setSelectedValue}
|
setSelectedValue={setSelectedValue}
|
||||||
type={"typeTags"}
|
|
||||||
onSmallBtnClick={() => {
|
onSmallBtnClick={() => {
|
||||||
setActiveItem(null);
|
setActiveItem(null);
|
||||||
setIsSelection(false);
|
setIsSelection(false);
|
||||||
@ -69,13 +70,14 @@ export const AmoStep7: FC<AmoStep7Props> = ({
|
|||||||
setActiveItem(null);
|
setActiveItem(null);
|
||||||
setIsSelection(false);
|
setIsSelection(false);
|
||||||
}}
|
}}
|
||||||
|
questions={questions}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<TagsDetailsView
|
<ItemDetailsView
|
||||||
setIsSelection={setIsSelection}
|
setIsSelection={setIsSelection}
|
||||||
handleLargeBtn={handleLargeBtn}
|
handleLargeBtn={handleNextStep}
|
||||||
handleSmallBtn={handleSmallBtn}
|
handleSmallBtn={handlePrevStep}
|
||||||
tags={tags}
|
questionEntity={questionEntity}
|
||||||
setActiveItem={setActiveItem}
|
setActiveItem={setActiveItem}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -4,19 +4,19 @@ import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock";
|
|||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { TQuestionEntity } from "../../AmoCRMModal";
|
import { TQuestionEntity } from "../../AmoCRMModal";
|
||||||
|
|
||||||
type TitleKeys = "contacts" | "company" | "deal" | "users" | "buyers";
|
type TitleKeys = "contacts" | "company" | "deal" | "buyers";
|
||||||
|
|
||||||
type ItemDetailsViewProps = {
|
type ItemDetailsViewProps = {
|
||||||
setIsSelection: (value: boolean) => void;
|
setIsSelection: (value: boolean) => void;
|
||||||
handlePrevStep: () => void;
|
handleSmallBtn: () => void;
|
||||||
handleNextStep: () => void;
|
handleLargeBtn: () => void;
|
||||||
questionEntity: TQuestionEntity;
|
questionEntity: TQuestionEntity;
|
||||||
setActiveItem: (value: string | null) => void;
|
setActiveItem: (value: string | null) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ItemDetailsView: FC<ItemDetailsViewProps> = ({
|
export const ItemDetailsView: FC<ItemDetailsViewProps> = ({
|
||||||
handlePrevStep,
|
handleSmallBtn,
|
||||||
handleNextStep,
|
handleLargeBtn,
|
||||||
questionEntity,
|
questionEntity,
|
||||||
setActiveItem,
|
setActiveItem,
|
||||||
setIsSelection,
|
setIsSelection,
|
||||||
@ -69,8 +69,9 @@ export const ItemDetailsView: FC<ItemDetailsViewProps> = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StepButtonsBlock
|
<StepButtonsBlock
|
||||||
onSmallBtnClick={handlePrevStep}
|
onSmallBtnClick={handleSmallBtn}
|
||||||
onLargeBtnClick={handleNextStep}
|
onLargeBtnClick={handleLargeBtn}
|
||||||
|
largeBtnText={"Сохранить"}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
@ -2,6 +2,7 @@ import { Box } from "@mui/material";
|
|||||||
import { CustomRadioGroup } from "../../../../../components/CustomRadioGroup/CustomRadioGroup";
|
import { CustomRadioGroup } from "../../../../../components/CustomRadioGroup/CustomRadioGroup";
|
||||||
import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock";
|
import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock";
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
|
import { AllTypesQuestion } from "@/model/questionTypes/shared";
|
||||||
|
|
||||||
type ItemsSelectionViewProps = {
|
type ItemsSelectionViewProps = {
|
||||||
type?: string;
|
type?: string;
|
||||||
@ -6,6 +6,7 @@ import { YandexMetricaLogo } from "../mocks/YandexMetricaLogo";
|
|||||||
import { VKPixelLogo } from "../mocks/VKPixelLogo";
|
import { VKPixelLogo } from "../mocks/VKPixelLogo";
|
||||||
import { QuizMetricType } from "@model/quizSettings";
|
import { QuizMetricType } from "@model/quizSettings";
|
||||||
import { AmoCRMLogo } from "../mocks/AmoCRMLogo";
|
import { AmoCRMLogo } from "../mocks/AmoCRMLogo";
|
||||||
|
import { useCurrentQuiz } from "@/stores/quizes/hooks";
|
||||||
|
|
||||||
const AnalyticsModal = lazy(() =>
|
const AnalyticsModal = lazy(() =>
|
||||||
import("./AnalyticsModal/AnalyticsModal").then((module) => ({
|
import("./AnalyticsModal/AnalyticsModal").then((module) => ({
|
||||||
@ -43,6 +44,8 @@ export const PartnersBoard: FC<PartnersBoardProps> = ({
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||||
|
|
||||||
|
const quiz = useCurrentQuiz();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -125,6 +128,7 @@ export const PartnersBoard: FC<PartnersBoardProps> = ({
|
|||||||
isModalOpen={isAmoCrmModalOpen}
|
isModalOpen={isAmoCrmModalOpen}
|
||||||
handleCloseModal={handleCloseAmoSRMModal}
|
handleCloseModal={handleCloseAmoSRMModal}
|
||||||
companyName={companyName}
|
companyName={companyName}
|
||||||
|
quizID={quiz?.backendId}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -4,13 +4,17 @@ import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
|||||||
import type { QuizQuestionDate } from "../../../model/questionTypes/date";
|
import type { QuizQuestionDate } from "../../../model/questionTypes/date";
|
||||||
|
|
||||||
type SettingsDataProps = {
|
type SettingsDataProps = {
|
||||||
question: QuizQuestionDate;
|
questionId: string;
|
||||||
|
isRequired: boolean;
|
||||||
|
isDateRange: boolean;
|
||||||
|
isTime: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function SettingsData({ question }: SettingsDataProps) {
|
export default function SettingsData({ questionId, isRequired, isDateRange, isTime }: SettingsDataProps) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
const isTablet = useMediaQuery(theme.breakpoints.down(900));
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -18,19 +22,66 @@ export default function SettingsData({ question }: SettingsDataProps) {
|
|||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
flexDirection: isWrappColumn ? "column" : null,
|
flexDirection: isTablet ? "column" : "row",
|
||||||
|
marginRight: isFigmaTablte ? (isMobile ? "0" : "0px") : "30px",
|
||||||
|
pb: "20px",
|
||||||
|
pl: "20px",
|
||||||
|
pt: isTablet ? "5px" : "0px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
boxSizing: "border-box",
|
||||||
pt: "20px",
|
pt: "20px",
|
||||||
pb: "20px",
|
|
||||||
pl: isFigmaTablte ? (isWrappColumn ? "20px" : "34px") : "20px",
|
|
||||||
pr: isFigmaTablte ? "19px" : "20px",
|
pr: isFigmaTablte ? "19px" : "20px",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
gap: isMobile ? "13px" : "14px",
|
gap: "14px",
|
||||||
width: isMobile ? "auto" : "100%",
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
height: isMobile ? "18px" : "auto",
|
||||||
|
fontWeight: "500",
|
||||||
|
fontSize: "18px",
|
||||||
|
color: " #4D4D4D",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Настройки ответов
|
||||||
|
</Typography>
|
||||||
|
<CustomCheckbox
|
||||||
|
dataCy="checkbox-dateRange"
|
||||||
|
sx={{ mr: isMobile ? "0px" : "16px" }}
|
||||||
|
label={"Выбор диапазона дат"}
|
||||||
|
checked={isDateRange}
|
||||||
|
handleChange={({ target }) => {
|
||||||
|
updateQuestion<QuizQuestionDate>(questionId, (question) => {
|
||||||
|
question.content.dateRange = target.checked;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<CustomCheckbox
|
||||||
|
dataCy="checkbox-time"
|
||||||
|
sx={{ mr: isMobile ? "0px" : "16px" }}
|
||||||
|
label={"Выбор времени"}
|
||||||
|
checked={isTime}
|
||||||
|
handleChange={({ target }) => {
|
||||||
|
updateQuestion<QuizQuestionDate>(questionId, (question) => {
|
||||||
|
question.content.time = target.checked;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
boxSizing: "border-box",
|
||||||
|
pt: "20px",
|
||||||
|
pr: isFigmaTablte ? "19px" : "20px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "14px",
|
||||||
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
@ -47,9 +98,9 @@ export default function SettingsData({ question }: SettingsDataProps) {
|
|||||||
dataCy="checkbox-optional-question"
|
dataCy="checkbox-optional-question"
|
||||||
sx={{ mr: isMobile ? "0px" : "16px" }}
|
sx={{ mr: isMobile ? "0px" : "16px" }}
|
||||||
label={"Необязательный вопрос"}
|
label={"Необязательный вопрос"}
|
||||||
checked={!question.content.required}
|
checked={!isRequired}
|
||||||
handleChange={({ target }) => {
|
handleChange={({ target }) => {
|
||||||
updateQuestion<QuizQuestionDate>(question.id, (question) => {
|
updateQuestion<QuizQuestionDate>(questionId, (question) => {
|
||||||
question.content.required = !target.checked;
|
question.content.required = !target.checked;
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -7,13 +7,17 @@ interface Props {
|
|||||||
question: QuizQuestionDate;
|
question: QuizQuestionDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SwitchData({
|
export default function SwitchData({ switchState = "setting", question }: Props) {
|
||||||
switchState = "setting",
|
|
||||||
question,
|
|
||||||
}: Props) {
|
|
||||||
switch (switchState) {
|
switch (switchState) {
|
||||||
case "setting":
|
case "setting":
|
||||||
return <SettingData question={question} />;
|
return (
|
||||||
|
<SettingData
|
||||||
|
questionId={question.id}
|
||||||
|
isRequired={question.content.required}
|
||||||
|
isDateRange={question.content.dateRange}
|
||||||
|
isTime={question.content.time}
|
||||||
|
/>
|
||||||
|
);
|
||||||
case "help":
|
case "help":
|
||||||
return (
|
return (
|
||||||
<HelpQuestions
|
<HelpQuestions
|
||||||
|
|||||||
@ -3,19 +3,20 @@ import { updateQuestion } from "@root/questions/actions";
|
|||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import type { QuizQuestionEmoji } from "../../../model/questionTypes/emoji";
|
import type { QuizQuestionEmoji } from "../../../model/questionTypes/emoji";
|
||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
|
import type { QuizQuestionVariant } from "@model/questionTypes/variant";
|
||||||
|
|
||||||
type SettingEmojiProps = {
|
type SettingEmojiProps = {
|
||||||
questionId: string;
|
questionId: string;
|
||||||
isRequired: boolean;
|
isRequired: boolean;
|
||||||
|
isMulti: boolean;
|
||||||
|
isOwn: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SettingEmoji = memo<SettingEmojiProps>(function ({
|
const SettingEmoji = memo<SettingEmojiProps>(function ({ questionId, isRequired, isMulti, isOwn }) {
|
||||||
questionId,
|
|
||||||
isRequired,
|
|
||||||
}) {
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
|
const isTablet = useMediaQuery(theme.breakpoints.down(985));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -24,13 +25,58 @@ const SettingEmoji = memo<SettingEmojiProps>(function ({
|
|||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
flexDirection: isWrappColumn ? "column" : "none",
|
flexDirection: isWrappColumn ? "column" : "none",
|
||||||
|
pb: "20px",
|
||||||
|
pl: "20px",
|
||||||
|
pt: isTablet ? "5px" : "0px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
boxSizing: "border-box",
|
||||||
|
pt: "20px",
|
||||||
|
pr: isFigmaTablte ? "19px" : "20px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "14px",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
height: isMobile ? "18px" : "auto",
|
||||||
|
fontWeight: "500",
|
||||||
|
fontSize: "18px",
|
||||||
|
color: " #4D4D4D",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Настройки ответов
|
||||||
|
</Typography>
|
||||||
|
<CustomCheckbox
|
||||||
|
dataCy="checkbox-multiple-answers"
|
||||||
|
sx={{ mr: isMobile ? "0px" : "16px" }}
|
||||||
|
label={"Можно несколько"}
|
||||||
|
checked={isMulti}
|
||||||
|
handleChange={({ target }) => {
|
||||||
|
updateQuestion<QuizQuestionVariant>(questionId, (question) => {
|
||||||
|
question.content.multi = target.checked;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<CustomCheckbox
|
||||||
|
dataCy="checkbox-own-answer"
|
||||||
|
sx={{ mr: isMobile ? "0px" : "16px" }}
|
||||||
|
label={'Вариант "свой ответ"'}
|
||||||
|
checked={isOwn}
|
||||||
|
handleChange={({ target }) => {
|
||||||
|
updateQuestion<QuizQuestionVariant>(questionId, (question) => {
|
||||||
|
question.content.own = target.checked;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
pt: "20px",
|
pt: "20px",
|
||||||
pb: "20px",
|
|
||||||
pl: "20px",
|
|
||||||
pr: isFigmaTablte ? "30px" : "20px",
|
pr: isFigmaTablte ? "30px" : "20px",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
|
|||||||
@ -7,16 +7,15 @@ interface Props {
|
|||||||
question: QuizQuestionEmoji;
|
question: QuizQuestionEmoji;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SwitchEmoji({
|
export default function SwitchEmoji({ switchState = "setting", question }: Props) {
|
||||||
switchState = "setting",
|
|
||||||
question,
|
|
||||||
}: Props) {
|
|
||||||
switch (switchState) {
|
switch (switchState) {
|
||||||
case "setting":
|
case "setting":
|
||||||
return (
|
return (
|
||||||
<SettingEmoji
|
<SettingEmoji
|
||||||
questionId={question.id}
|
questionId={question.id}
|
||||||
isRequired={question.content.required}
|
isRequired={question.content.required}
|
||||||
|
isOwn={question.content.own}
|
||||||
|
isMulti={question.content.multi}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "help":
|
case "help":
|
||||||
|
|||||||
@ -4,21 +4,20 @@ import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
|||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
import type { QuizQuestionVarImg } from "../../../model/questionTypes/varimg";
|
import type { QuizQuestionVarImg } from "../../../model/questionTypes/varimg";
|
||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
|
import type { QuizQuestionVariant } from "@model/questionTypes/variant";
|
||||||
|
|
||||||
type SettingOptionsAndPictProps = {
|
type SettingOptionsAndPictProps = {
|
||||||
questionId: string;
|
questionId: string;
|
||||||
replText: string;
|
replText: string;
|
||||||
isRequired: boolean;
|
isRequired: boolean;
|
||||||
|
isOwn: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({
|
const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({ questionId, replText, isRequired, isOwn }) {
|
||||||
questionId,
|
|
||||||
replText,
|
|
||||||
isRequired,
|
|
||||||
}) {
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
|
const isTablet = useMediaQuery(theme.breakpoints.down(985));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(680));
|
const isMobile = useMediaQuery(theme.breakpoints.down(680));
|
||||||
|
|
||||||
const setReplText = (replText: string) => {
|
const setReplText = (replText: string) => {
|
||||||
@ -36,13 +35,14 @@ const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({
|
|||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
flexDirection: isWrappColumn ? "column" : "none",
|
flexDirection: isWrappColumn ? "column" : "none",
|
||||||
|
pb: "20px",
|
||||||
|
pl: "20px",
|
||||||
|
pt: isTablet ? "5px" : "0px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
pt: isMobile ? "30px" : "20px",
|
pt: "20px",
|
||||||
pb: isMobile ? "25px" : "20px",
|
|
||||||
pl: "20px",
|
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
gap: "14px",
|
gap: "14px",
|
||||||
@ -60,6 +60,17 @@ const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({
|
|||||||
>
|
>
|
||||||
Настройки ответов
|
Настройки ответов
|
||||||
</Typography>
|
</Typography>
|
||||||
|
<CustomCheckbox
|
||||||
|
dataCy="checkbox-own-answer"
|
||||||
|
sx={{ mr: isMobile ? "0px" : "16px" }}
|
||||||
|
label={'Вариант "свой ответ"'}
|
||||||
|
checked={isOwn}
|
||||||
|
handleChange={({ target }) => {
|
||||||
|
updateQuestion<QuizQuestionVariant>(questionId, (question) => {
|
||||||
|
question.content.own = target.checked;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
{!isWrappColumn && (
|
{!isWrappColumn && (
|
||||||
<Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
|
<Box sx={{ mt: isMobile ? "11px" : "6px", width: "100%" }}>
|
||||||
<Typography
|
<Typography
|
||||||
@ -90,8 +101,6 @@ const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({
|
|||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
pt: isMobile ? "0px" : "20px",
|
pt: isMobile ? "0px" : "20px",
|
||||||
pb: "20px",
|
|
||||||
pl: isFigmaTablte ? (isWrappColumn ? "20px" : "31px") : "20px",
|
|
||||||
pr: isFigmaTablte ? "19px" : "20px",
|
pr: isFigmaTablte ? "19px" : "20px",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
@ -123,7 +132,16 @@ const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{isWrappColumn && (
|
{isWrappColumn && (
|
||||||
<>
|
<Box
|
||||||
|
sx={{
|
||||||
|
pt: "20px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "14px",
|
||||||
|
maxWidth: isFigmaTablte ? "297px" : "360px",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
height: isMobile ? "18px" : "auto",
|
height: isMobile ? "18px" : "auto",
|
||||||
@ -141,7 +159,7 @@ const SettingOptionsAndPict = memo<SettingOptionsAndPictProps>(function ({
|
|||||||
maxLength={60}
|
maxLength={60}
|
||||||
onChange={({ target }) => setReplText(target.value)}
|
onChange={({ target }) => setReplText(target.value)}
|
||||||
/>
|
/>
|
||||||
</>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@ -8,10 +8,7 @@ interface Props {
|
|||||||
question: QuizQuestionVarImg;
|
question: QuizQuestionVarImg;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SwitchOptionsAndPict({
|
export default function SwitchOptionsAndPict({ switchState = "setting", question }: Props) {
|
||||||
switchState = "setting",
|
|
||||||
question,
|
|
||||||
}: Props) {
|
|
||||||
switch (switchState) {
|
switch (switchState) {
|
||||||
case "setting":
|
case "setting":
|
||||||
return (
|
return (
|
||||||
@ -19,6 +16,7 @@ export default function SwitchOptionsAndPict({
|
|||||||
questionId={question.id}
|
questionId={question.id}
|
||||||
replText={question.content.replText}
|
replText={question.content.replText}
|
||||||
isRequired={question.content.required}
|
isRequired={question.content.required}
|
||||||
|
isOwn={question.content.own}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "help":
|
case "help":
|
||||||
@ -30,12 +28,7 @@ export default function SwitchOptionsAndPict({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "image":
|
case "image":
|
||||||
return (
|
return <UploadImage question={question} cropAspectRatio={{ width: 380, height: 300 }} />;
|
||||||
<UploadImage
|
|
||||||
question={question}
|
|
||||||
cropAspectRatio={{ width: 380, height: 300 }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,4 @@
|
|||||||
import {
|
import { Box, Button, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Typography,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { updateQuestion } from "@root/questions/actions";
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import ProportionsIcon11 from "../../../assets/icons/questionsPage/ProportionsIcon11";
|
import ProportionsIcon11 from "../../../assets/icons/questionsPage/ProportionsIcon11";
|
||||||
@ -12,6 +6,9 @@ import ProportionsIcon12 from "../../../assets/icons/questionsPage/ProportionsIc
|
|||||||
import ProportionsIcon21 from "../../../assets/icons/questionsPage/ProportionsIcon21";
|
import ProportionsIcon21 from "../../../assets/icons/questionsPage/ProportionsIcon21";
|
||||||
import type { QuizQuestionImages } from "../../../model/questionTypes/images";
|
import type { QuizQuestionImages } from "../../../model/questionTypes/images";
|
||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
|
import type { QuizQuestionVariant } from "@model/questionTypes/variant";
|
||||||
|
import FormatIcon1 from "../../../assets/icons/questionsPage/FormatIcon1";
|
||||||
|
import FormatIcon2 from "../../../assets/icons/questionsPage/FormatIcon2";
|
||||||
|
|
||||||
type Proportion = "1:1" | "2:1" | "1:2";
|
type Proportion = "1:1" | "2:1" | "1:2";
|
||||||
|
|
||||||
@ -26,14 +23,34 @@ const PROPORTIONS: ProportionItem[] = [
|
|||||||
{ value: "1:2", icon: ProportionsIcon12 },
|
{ value: "1:2", icon: ProportionsIcon12 },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
type Format = "carousel" | "masonry";
|
||||||
|
|
||||||
|
type FormatItem = {
|
||||||
|
value: Format;
|
||||||
|
icon: (props: { color: string }) => JSX.Element;
|
||||||
|
};
|
||||||
|
|
||||||
|
const FORMATS: FormatItem[] = [
|
||||||
|
{ value: "masonry", icon: FormatIcon2 },
|
||||||
|
{ value: "carousel", icon: FormatIcon1 },
|
||||||
|
];
|
||||||
|
|
||||||
type SettingOpytionsPictProps = {
|
type SettingOpytionsPictProps = {
|
||||||
questionId: string;
|
questionId: string;
|
||||||
isRequired: boolean;
|
isRequired: boolean;
|
||||||
|
isMulti: boolean;
|
||||||
|
isOwn: boolean;
|
||||||
|
proportions: Proportion;
|
||||||
|
format: Format;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SettingOptionsPict = memo<SettingOpytionsPictProps>(function ({
|
const SettingOptionsPict = memo<SettingOpytionsPictProps>(function ({
|
||||||
questionId,
|
questionId,
|
||||||
isRequired,
|
isRequired,
|
||||||
|
isMulti,
|
||||||
|
isOwn,
|
||||||
|
proportions,
|
||||||
|
format,
|
||||||
}) {
|
}) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(985));
|
const isTablet = useMediaQuery(theme.breakpoints.down(985));
|
||||||
@ -47,38 +64,167 @@ const SettingOptionsPict = memo<SettingOpytionsPictProps>(function ({
|
|||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
flexDirection: isTablet ? "column" : null,
|
flexDirection: isTablet ? "column" : null,
|
||||||
marginRight: isFigmaTablte ? (isMobile ? "0" : "0px") : "30px",
|
marginRight: isFigmaTablte ? (isMobile ? "0" : "0px") : "30px",
|
||||||
|
pb: "20px",
|
||||||
|
pl: "20px",
|
||||||
|
pt: isTablet ? "5px" : "0px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
|
||||||
sx={{
|
<Box
|
||||||
pt: isMobile ? "25px" : "20px",
|
sx={{
|
||||||
pb: isMobile ? "25px" : "20px",
|
boxSizing: "border-box",
|
||||||
pl: "20px",
|
pt: "20px",
|
||||||
pr: isFigmaTablte ? (isMobile ? "20px" : "0px") : "28px",
|
pr: isFigmaTablte ? "19px" : "20px",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
gap: "14px",
|
gap: "14px",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
sx={{ fontWeight: "500", fontSize: "18px", color: " #4D4D4D" }}
|
|
||||||
>
|
>
|
||||||
Настройки вопросов
|
<Typography
|
||||||
</Typography>
|
sx={{
|
||||||
<CustomCheckbox
|
height: isMobile ? "18px" : "auto",
|
||||||
dataCy="checkbox-optional-question"
|
fontWeight: "500",
|
||||||
sx={{ alignItems: isMobile ? "flex-start" : "" }}
|
fontSize: "18px",
|
||||||
label={"Необязательный вопрос"}
|
color: " #4D4D4D",
|
||||||
checked={!isRequired}
|
}}
|
||||||
handleChange={({ target }) =>
|
>
|
||||||
updateQuestion<QuizQuestionImages>(questionId, (question) => {
|
Пропорции
|
||||||
if (question.type !== "images") return;
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
gap: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{PROPORTIONS.map((proportionItem, index) => (
|
||||||
|
<SelectIconButton
|
||||||
|
key={index}
|
||||||
|
Icon={proportionItem.icon}
|
||||||
|
isActive={proportionItem.value === proportions}
|
||||||
|
onClick={() => {
|
||||||
|
updateQuestion<QuizQuestionImages>(questionId, (question) => {
|
||||||
|
if (question.type !== "images") return;
|
||||||
|
question.content.xy = proportionItem.value;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
boxSizing: "border-box",
|
||||||
|
pt: "20px",
|
||||||
|
pr: isFigmaTablte ? "19px" : "20px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "14px",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
height: isMobile ? "18px" : "auto",
|
||||||
|
fontWeight: "500",
|
||||||
|
fontSize: "18px",
|
||||||
|
color: " #4D4D4D",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Настройки ответов
|
||||||
|
</Typography>
|
||||||
|
<CustomCheckbox
|
||||||
|
dataCy="checkbox-multiple-answers"
|
||||||
|
sx={{ mr: isMobile ? "0px" : "16px" }}
|
||||||
|
label={"Можно несколько"}
|
||||||
|
checked={isMulti}
|
||||||
|
handleChange={({ target }) => {
|
||||||
|
updateQuestion<QuizQuestionVariant>(questionId, (question) => {
|
||||||
|
question.content.multi = target.checked;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<CustomCheckbox
|
||||||
|
dataCy="checkbox-own-answer"
|
||||||
|
sx={{ mr: isMobile ? "0px" : "16px" }}
|
||||||
|
label={'Вариант "свой ответ"'}
|
||||||
|
checked={isOwn}
|
||||||
|
handleChange={({ target }) => {
|
||||||
|
updateQuestion<QuizQuestionVariant>(questionId, (question) => {
|
||||||
|
question.content.own = target.checked;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
boxSizing: "border-box",
|
||||||
|
pt: "20px",
|
||||||
|
pr: isFigmaTablte ? "19px" : "20px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "14px",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
height: isMobile ? "18px" : "auto",
|
||||||
|
fontWeight: "500",
|
||||||
|
fontSize: "18px",
|
||||||
|
color: " #4D4D4D",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Формат
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
gap: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{FORMATS.map((formatItem, index) => (
|
||||||
|
<SelectIconButton
|
||||||
|
key={index}
|
||||||
|
Icon={formatItem.icon}
|
||||||
|
isActive={formatItem.value === format}
|
||||||
|
onClick={() => {
|
||||||
|
updateQuestion<QuizQuestionImages>(questionId, (question) => {
|
||||||
|
if (question.type !== "images") return;
|
||||||
|
question.content.format = formatItem.value;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
pt: "20px",
|
||||||
|
pr: isFigmaTablte ? (isMobile ? "20px" : "0px") : "28px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "14px",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography sx={{ fontWeight: "500", fontSize: "18px", color: " #4D4D4D" }}>Настройки вопросов</Typography>
|
||||||
|
<CustomCheckbox
|
||||||
|
dataCy="checkbox-optional-question"
|
||||||
|
sx={{ alignItems: isMobile ? "flex-start" : "" }}
|
||||||
|
label={"Необязательный вопрос"}
|
||||||
|
checked={!isRequired}
|
||||||
|
handleChange={({ target }) =>
|
||||||
|
updateQuestion<QuizQuestionImages>(questionId, (question) => {
|
||||||
|
if (question.type !== "images") return;
|
||||||
|
|
||||||
question.content.required = !target.checked;
|
question.content.required = !target.checked;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
@ -101,23 +247,13 @@ export function SelectIconButton({ Icon, isActive = false, onClick }: Props) {
|
|||||||
<Button
|
<Button
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
startIcon={
|
startIcon={<Icon color={isActive ? theme.palette.navbarbg.main : theme.palette.brightPurple.main} />}
|
||||||
<Icon
|
|
||||||
color={
|
|
||||||
isActive
|
|
||||||
? theme.palette.navbarbg.main
|
|
||||||
: theme.palette.brightPurple.main
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: isActive ? theme.palette.brightPurple.main : "#eee4fc",
|
backgroundColor: isActive ? theme.palette.brightPurple.main : "#eee4fc",
|
||||||
|
|
||||||
borderRadius: 0,
|
borderRadius: 0,
|
||||||
border: "none",
|
border: "none",
|
||||||
color: isActive
|
color: isActive ? theme.palette.brightPurple.main : theme.palette.grey2.main,
|
||||||
? theme.palette.brightPurple.main
|
|
||||||
: theme.palette.grey2.main,
|
|
||||||
p: "7px",
|
p: "7px",
|
||||||
width: "40px",
|
width: "40px",
|
||||||
height: "40px",
|
height: "40px",
|
||||||
@ -128,9 +264,7 @@ export function SelectIconButton({ Icon, isActive = false, onClick }: Props) {
|
|||||||
},
|
},
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
border: "none",
|
border: "none",
|
||||||
borderColor: isActive
|
borderColor: isActive ? theme.palette.brightPurple.main : theme.palette.grey2.main,
|
||||||
? theme.palette.brightPurple.main
|
|
||||||
: theme.palette.grey2.main,
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -7,16 +7,17 @@ interface Props {
|
|||||||
question: QuizQuestionImages;
|
question: QuizQuestionImages;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SwitchAnswerOptionsPict({
|
export default function SwitchAnswerOptionsPict({ switchState = "setting", question }: Props) {
|
||||||
switchState = "setting",
|
|
||||||
question,
|
|
||||||
}: Props) {
|
|
||||||
switch (switchState) {
|
switch (switchState) {
|
||||||
case "setting":
|
case "setting":
|
||||||
return (
|
return (
|
||||||
<SettingOpytionsPict
|
<SettingOpytionsPict
|
||||||
questionId={question.id}
|
questionId={question.id}
|
||||||
isRequired={question.content.required}
|
isRequired={question.content.required}
|
||||||
|
isMulti={question.content.multi}
|
||||||
|
isOwn={question.content.own}
|
||||||
|
proportions={question.content.xy}
|
||||||
|
format={question.content.format}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "help":
|
case "help":
|
||||||
|
|||||||
@ -1,31 +1,36 @@
|
|||||||
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
import { Box, FormControlLabel, Radio, RadioGroup, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
import { updateQuestion } from "@root/questions/actions";
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import type { QuizQuestionText } from "../../../model/questionTypes/text";
|
import type { QuizQuestionText } from "../../../model/questionTypes/text";
|
||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
|
import RadioCheck from "@ui_kit/RadioCheck";
|
||||||
|
import RadioIcon from "@ui_kit/RadioIcon";
|
||||||
|
|
||||||
|
type Answer = "single" | "multi" | "numberOnly";
|
||||||
|
|
||||||
|
type AnswerItem = {
|
||||||
|
name: string;
|
||||||
|
value: Answer;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ANSWER_TYPES: AnswerItem[] = [
|
||||||
|
{ name: "Однострочное", value: "single" },
|
||||||
|
{ name: "Многострочное", value: "multi" },
|
||||||
|
{ name: "Только числа", value: "numberOnly" },
|
||||||
|
];
|
||||||
|
|
||||||
type SettingTextFieldProps = {
|
type SettingTextFieldProps = {
|
||||||
questionId: string;
|
questionId: string;
|
||||||
isRequired: boolean;
|
isRequired: boolean;
|
||||||
|
isAutofill: boolean;
|
||||||
|
answerType: Answer;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Answer = {
|
const SettingTextField = memo<SettingTextFieldProps>(function ({ questionId, isRequired, isAutofill, answerType }) {
|
||||||
name: string;
|
|
||||||
value: "single" | "multi";
|
|
||||||
};
|
|
||||||
|
|
||||||
const ANSWER_TYPES: Answer[] = [
|
|
||||||
{ name: "Однострочное", value: "single" },
|
|
||||||
{ name: "Многострочное", value: "multi" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const SettingTextField = memo<SettingTextFieldProps>(function ({
|
|
||||||
questionId,
|
|
||||||
isRequired,
|
|
||||||
}) {
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
const isTablet = useMediaQuery(theme.breakpoints.down(900));
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -33,19 +38,67 @@ const SettingTextField = memo<SettingTextFieldProps>(function ({
|
|||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
flexDirection: isWrappColumn ? "column" : null,
|
flexDirection: isTablet ? "column" : "row",
|
||||||
marginRight: isFigmaTablte ? "0px" : "32px",
|
marginRight: isFigmaTablte ? (isMobile ? "0" : "0px") : "30px",
|
||||||
|
pb: "20px",
|
||||||
|
pl: "20px",
|
||||||
|
pt: isTablet ? "5px" : "0px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
boxSizing: "border-box",
|
||||||
pt: "20px",
|
pt: "20px",
|
||||||
pb: "20px",
|
pr: isFigmaTablte ? "19px" : "20px",
|
||||||
pl: isFigmaTablte ? (isWrappColumn ? "20px" : "34px") : "20px",
|
|
||||||
pr: "20px",
|
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
gap: "14px",
|
gap: "14px",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
height: isMobile ? "18px" : "auto",
|
||||||
|
fontWeight: "500",
|
||||||
|
fontSize: "18px",
|
||||||
|
color: " #4D4D4D",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Настройки ответов
|
||||||
|
</Typography>
|
||||||
|
<RadioGroup
|
||||||
|
value={answerType}
|
||||||
|
onChange={(event) => {
|
||||||
|
updateQuestion<QuizQuestionText>(questionId, (question) => {
|
||||||
|
question.content.answerType = event.target.value as Answer;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ANSWER_TYPES.map((answerTypeItem, index) => (
|
||||||
|
<FormControlLabel
|
||||||
|
value={answerTypeItem.value}
|
||||||
|
control={<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />}
|
||||||
|
label={answerTypeItem.name}
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.grey2.main,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</RadioGroup>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
boxSizing: "border-box",
|
||||||
|
pt: "20px",
|
||||||
|
pr: isFigmaTablte ? "19px" : "20px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "14px",
|
||||||
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
@ -58,6 +111,21 @@ const SettingTextField = memo<SettingTextFieldProps>(function ({
|
|||||||
>
|
>
|
||||||
Настройки вопросов
|
Настройки вопросов
|
||||||
</Typography>
|
</Typography>
|
||||||
|
<CustomCheckbox
|
||||||
|
dataCy="checkbox-optional-autofill"
|
||||||
|
sx={{
|
||||||
|
display: isMobile ? "flex" : "block",
|
||||||
|
mr: isMobile ? "0px" : "16px",
|
||||||
|
alignItems: isMobile ? "flex-end" : "center",
|
||||||
|
}}
|
||||||
|
label={"Автозаполнение адреса"}
|
||||||
|
checked={isAutofill}
|
||||||
|
handleChange={(e) => {
|
||||||
|
updateQuestion<QuizQuestionText>(questionId, (question) => {
|
||||||
|
question.content.autofill = e.target.checked;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<CustomCheckbox
|
<CustomCheckbox
|
||||||
dataCy="checkbox-optional-question"
|
dataCy="checkbox-optional-question"
|
||||||
sx={{
|
sx={{
|
||||||
|
|||||||
@ -8,25 +8,20 @@ interface Props {
|
|||||||
question: QuizQuestionText;
|
question: QuizQuestionText;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SwitchTextField({
|
export default function SwitchTextField({ switchState = "setting", question }: Props) {
|
||||||
switchState = "setting",
|
|
||||||
question,
|
|
||||||
}: Props) {
|
|
||||||
switch (switchState) {
|
switch (switchState) {
|
||||||
case "setting":
|
case "setting":
|
||||||
return (
|
return (
|
||||||
<SettingTextField
|
<SettingTextField
|
||||||
questionId={question.id}
|
questionId={question.id}
|
||||||
isRequired={question.content.required}
|
isRequired={question.content.required}
|
||||||
|
isAutofill={question.content.autofill}
|
||||||
|
isOnlyNumbers={question.content.onlyNumbers}
|
||||||
|
answerType={question.content.answerType}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "image":
|
case "image":
|
||||||
return (
|
return <UploadImage question={question} cropAspectRatio={{ width: 400, height: 300 }} />;
|
||||||
<UploadImage
|
|
||||||
question={question}
|
|
||||||
cropAspectRatio={{ width: 400, height: 300 }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case "help":
|
case "help":
|
||||||
return (
|
return (
|
||||||
<HelpQuestions
|
<HelpQuestions
|
||||||
|
|||||||
@ -7,9 +7,12 @@ import { memo } from "react";
|
|||||||
interface Props {
|
interface Props {
|
||||||
questionId: string;
|
questionId: string;
|
||||||
isRequired: boolean;
|
isRequired: boolean;
|
||||||
|
isLargeCheck: boolean;
|
||||||
|
isMulti: boolean;
|
||||||
|
isOwn: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ResponseSettings = memo<Props>(function ({ questionId, isRequired }) {
|
const ResponseSettings = memo<Props>(function ({ questionId, isRequired, isLargeCheck, isMulti, isOwn }) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(900));
|
const isTablet = useMediaQuery(theme.breakpoints.down(900));
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
@ -20,16 +23,72 @@ const ResponseSettings = memo<Props>(function ({ questionId, isRequired }) {
|
|||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
flexDirection: isTablet ? "column" : "none",
|
flexDirection: isTablet ? "column" : "row",
|
||||||
marginRight: isFigmaTablte ? (isMobile ? "0" : "0px") : "30px",
|
marginRight: isFigmaTablte ? (isMobile ? "0" : "0px") : "30px",
|
||||||
|
pb: "20px",
|
||||||
|
pl: "20px",
|
||||||
|
pt: isTablet ? "5px" : "0px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
boxSizing: "border-box",
|
boxSizing: "border-box",
|
||||||
pt: "20px",
|
pt: "20px",
|
||||||
pb: "20px",
|
pr: isFigmaTablte ? "19px" : "20px",
|
||||||
pl: isFigmaTablte ? (isTablet ? "20px" : "34px") : "28px",
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "14px",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
height: isMobile ? "18px" : "auto",
|
||||||
|
fontWeight: "500",
|
||||||
|
fontSize: "18px",
|
||||||
|
color: " #4D4D4D",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Настройки ответов
|
||||||
|
</Typography>
|
||||||
|
<CustomCheckbox
|
||||||
|
dataCy="checkbox-long-text-answer"
|
||||||
|
sx={{ mr: isMobile ? "0px" : "16px" }}
|
||||||
|
label={"Длинный текстовый ответ"}
|
||||||
|
checked={isLargeCheck}
|
||||||
|
handleChange={({ target }) => {
|
||||||
|
updateQuestion<QuizQuestionVariant>(questionId, (question) => {
|
||||||
|
question.content.largeCheck = target.checked;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<CustomCheckbox
|
||||||
|
dataCy="checkbox-multiple-answers"
|
||||||
|
sx={{ mr: isMobile ? "0px" : "16px" }}
|
||||||
|
label={"Можно несколько"}
|
||||||
|
checked={isMulti}
|
||||||
|
handleChange={({ target }) => {
|
||||||
|
updateQuestion<QuizQuestionVariant>(questionId, (question) => {
|
||||||
|
question.content.multi = target.checked;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<CustomCheckbox
|
||||||
|
dataCy="checkbox-own-answer"
|
||||||
|
sx={{ mr: isMobile ? "0px" : "16px" }}
|
||||||
|
label={'Вариант "свой ответ"'}
|
||||||
|
checked={isOwn}
|
||||||
|
handleChange={({ target }) => {
|
||||||
|
updateQuestion<QuizQuestionVariant>(questionId, (question) => {
|
||||||
|
question.content.own = target.checked;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
boxSizing: "border-box",
|
||||||
|
pt: "20px",
|
||||||
pr: isFigmaTablte ? "19px" : "20px",
|
pr: isFigmaTablte ? "19px" : "20px",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
|
|||||||
@ -8,16 +8,16 @@ interface Props {
|
|||||||
question: QuizQuestionVariant;
|
question: QuizQuestionVariant;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SwitchAnswerOptions({
|
export default function SwitchAnswerOptions({ switchState = "setting", question }: Props) {
|
||||||
switchState = "setting",
|
|
||||||
question,
|
|
||||||
}: Props) {
|
|
||||||
switch (switchState) {
|
switch (switchState) {
|
||||||
case "setting":
|
case "setting":
|
||||||
return (
|
return (
|
||||||
<ResponseSettings
|
<ResponseSettings
|
||||||
questionId={question.id}
|
questionId={question.id}
|
||||||
isRequired={question.content.required}
|
isRequired={question.content.required}
|
||||||
|
isLargeCheck={question.content.largeCheck}
|
||||||
|
isMulti={question.content.multi}
|
||||||
|
isOwn={question.content.own}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "help":
|
case "help":
|
||||||
@ -29,12 +29,7 @@ export default function SwitchAnswerOptions({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "image":
|
case "image":
|
||||||
return (
|
return <UploadImage question={question} cropAspectRatio={{ width: 380, height: 300 }} />;
|
||||||
<UploadImage
|
|
||||||
question={question}
|
|
||||||
cropAspectRatio={{ width: 380, height: 300 }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { ButtonBase } from "@mui/material";
|
import { ButtonBase, Popover } from "@mui/material";
|
||||||
import { startTransition, useRef } from "react";
|
import { startTransition, useState } from "react";
|
||||||
|
import { HexAlphaColorPicker } from "react-colorful";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
color: string;
|
color: string;
|
||||||
@ -7,35 +8,43 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function CircleColorPicker({ color, onChange }: Props) {
|
export default function CircleColorPicker({ color, onChange }: Props) {
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonBase
|
<>
|
||||||
onClick={() => inputRef.current?.click()}
|
<ButtonBase
|
||||||
sx={{
|
onClick={(event) => setAnchorEl(event.currentTarget)}
|
||||||
aspectRatio: 1,
|
sx={{
|
||||||
height: "22px",
|
aspectRatio: 1,
|
||||||
width: "22px",
|
height: "22px",
|
||||||
minWidth: "22px",
|
width: "22px",
|
||||||
borderRadius: "50%",
|
minWidth: "22px",
|
||||||
backgroundColor: color,
|
borderRadius: "50%",
|
||||||
border: "1px solid #4D4D4D",
|
backgroundColor: color,
|
||||||
}}
|
border: "1px solid #4D4D4D",
|
||||||
>
|
|
||||||
<input
|
|
||||||
ref={inputRef}
|
|
||||||
type="color"
|
|
||||||
value={color}
|
|
||||||
onChange={(e) => {
|
|
||||||
startTransition(() => {
|
|
||||||
onChange(e.target.value);
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
opacity: 0,
|
|
||||||
cursor: "pointer",
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ButtonBase>
|
<Popover
|
||||||
|
open={Boolean(anchorEl)}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
onClose={() => setAnchorEl(null)}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: "bottom",
|
||||||
|
horizontal: "right",
|
||||||
|
}}
|
||||||
|
slotProps={{
|
||||||
|
paper: {
|
||||||
|
sx: {
|
||||||
|
p: "20px",
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
backgroundColor: color,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<HexAlphaColorPicker color={color} onChange={(color) => startTransition(() => onChange(color))} />
|
||||||
|
</Popover>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ const translateMessage: Record<string, string> = {
|
|||||||
|
|
||||||
export const parseAxiosError = (nativeError: unknown): [string, number?] => {
|
export const parseAxiosError = (nativeError: unknown): [string, number?] => {
|
||||||
const error = nativeError as AxiosError;
|
const error = nativeError as AxiosError;
|
||||||
|
console.log(error)
|
||||||
if (process.env.NODE_ENV !== "production") console.error(error);
|
if (process.env.NODE_ENV !== "production") console.error(error);
|
||||||
if (error.message === "Failed to fetch") return ["Ошибка сети"];
|
if (error.message === "Failed to fetch") return ["Ошибка сети"];
|
||||||
|
|
||||||
|
|||||||
@ -9486,6 +9486,11 @@ react-beautiful-dnd@^13.1.1:
|
|||||||
redux "^4.0.4"
|
redux "^4.0.4"
|
||||||
use-memo-one "^1.1.1"
|
use-memo-one "^1.1.1"
|
||||||
|
|
||||||
|
react-colorful@^5.6.1:
|
||||||
|
version "5.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.6.1.tgz#7dc2aed2d7c72fac89694e834d179e32f3da563b"
|
||||||
|
integrity sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==
|
||||||
|
|
||||||
react-cytoscapejs@^2.0.0:
|
react-cytoscapejs@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-cytoscapejs/-/react-cytoscapejs-2.0.0.tgz#fdc2547626df0678acfbb48e73a437ddc1687b01"
|
resolved "https://registry.yarnpkg.com/react-cytoscapejs/-/react-cytoscapejs-2.0.0.tgz#fdc2547626df0678acfbb48e73a437ddc1687b01"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user