Merge branch 'dev' of penahub.gitlab.yandexcloud.net:frontend/squiz into dev

This commit is contained in:
IlyaDoronin 2024-02-02 09:30:33 +03:00
commit 38c40d1dfe
61 changed files with 820 additions and 516 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

BIN
public/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

71
public/favicon.svg Normal file

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="43.585045"
height="39.566273"
viewBox="0 0 63.268614 57.700814"
fill="none"
version="1.1"
id="svg8"
sodipodi:docname="favicon.svg"
inkscape:export-filename="favicon.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview8"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showguides="true" />
<g
clip-path="url(#clip0_316_1239)"
id="g8"
transform="translate(-1.6513393,-3.2563442)">
<g
id="g9"
transform="translate(0.27803262,-0.00871564)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M 25.9138,3.31956 C 18.594,2.47167 13.5439,10.3345 8.84663,16.0182 4.72431,21.0062 1.6549,26.6402 1.29838,33.1042 0.919075,39.9813 2.16658,47.1435 6.85174,52.1873 11.6777,57.3827 18.9068,60.6653 25.9138,59.604 32.3391,58.6308 35.1822,51.5749 39.9658,47.1716 45.16,42.3905 54.837,40.1668 54.7027,33.1042 54.5683,26.0308 44.3552,24.6463 39.441,19.5621 34.3509,14.2959 33.1853,4.16185 25.9138,3.31956 Z"
fill="#7e2aea"
id="path1" />
<circle
cx="44.125999"
cy="56.918098"
r="4.0390601"
fill="#7e2aea"
id="circle1" />
<circle
cx="40.086498"
cy="12.1038"
r="1.53869"
fill="#7e2aea"
id="circle2" />
<path
d="m 64.699,31.4509 c -0.4487,-4.3618 -2.5007,-8.4017 -5.7585,-11.3366 -3.2577,-2.9349 -7.4891,-4.5558 -11.8739,-4.5485 -0.6225,3e-4 -1.2446,0.0329 -1.8638,0.0976 -4.3599,0.4578 -8.3958,2.5137 -11.3293,5.7713 -2.9336,3.2577 -4.557,7.4861 -4.5571,11.8699 v 0 25.3412 h 7.6024 v -10.77 c 2.9724,2.0679 6.5079,3.1735 10.1288,3.1676 0.6226,-2e-4 1.2447,-0.0327 1.8639,-0.0975 2.3167,-0.2435 4.5629,-0.9409 6.6101,-2.0525 2.0472,-1.1116 3.8555,-2.6155 5.3215,-4.4259 1.466,-1.8104 2.5611,-3.8918 3.2227,-6.1254 0.6616,-2.2336 0.8767,-4.5757 0.6332,-6.8924 z m -9.764,8.2359 c -0.8351,1.0374 -1.8677,1.8988 -3.038,2.5343 -1.1704,0.6355 -2.4552,1.0325 -3.78,1.168 -0.3553,0.0369 -0.7122,0.0555 -1.0694,0.0558 -2.2991,-0.0021 -4.5293,-0.7858 -6.3243,-2.2224 -1.7951,-1.4366 -3.0484,-3.4408 -3.5544,-5.6836 -0.5059,-2.2428 -0.2343,-4.5909 0.7702,-6.6591 1.0045,-2.0681 2.6822,-3.7333 4.7578,-4.7222 2.0756,-0.9889 4.4257,-1.2429 6.6647,-0.7202 2.2389,0.5228 4.2336,1.7911 5.6567,3.5969 1.4231,1.8058 2.19,4.0417 2.1749,6.3408 -0.0151,2.2991 -0.8114,4.5248 -2.2582,6.3117 z"
fill="#000000"
id="path2" />
</g>
</g>
<defs
id="defs8">
<clipPath
id="clip0_316_1239">
<rect
width="179.509"
height="69.487198"
fill="#ffffff"
id="rect8"
x="0"
y="0" />
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
public/favicon192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
public/favicon512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@ -2,18 +2,45 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<title>Pena Quiz</title>
<meta name="description" content="Веб-сервис с инструментами для повышения эффективности маркетологов."/>
<meta name="keywords" content=" Экосистема маркетинговых инструментов,
Инструменты для социальных исследований,
Малый бизнес,
Маркетинговые инструменты,
Социальные исследования,
Бизнес-инструменты,
Исследование рынка,
Аналитика бизнеса,
Онлайн-маркетинг,
Исследования рынка,
Продвижение бизнеса,
Реклама и маркетинг,
Управление проектами,
Автоматизация процессов,
Оптимизация бюджета,
Планирование стратегии,
Оценка эффективности,
Анализ данных,
Улучшение результатов,
Увеличение прибыли,
Повышение конкурентоспособности "/>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" sizes="any"/><!-- 32×32 -->
<link rel="icon" href="%PUBLIC_URL%/favicon.svg" type="image/svg+xml"/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/favicon.png"/><!-- 180×180 -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Rubik:wght@400;500;600&display=swap"
rel="stylesheet"
/>
<title>Pena Quiz</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

23
public/manifest.json Executable file → Normal file

@ -1,23 +1,10 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"short_name": "PenaHub",
"name": "Pena Hub",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "android-chrome-192x192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "android-chrome-512x512.png",
"type": "image/png",
"sizes": "512x512"
}
],
{ "src": "/favicon192.png", "type": "image/png", "sizes": "192x192" },
{ "src": "/favicon512.png", "type": "image/png", "sizes": "512x512" }
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

@ -1,48 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="576.000000pt" height="576.000000pt" viewBox="0 0 576.000000 576.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.14, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,576.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M1980 5475 c-206 -46 -387 -146 -578 -320 -83 -75 -199 -195 -272
-281 -48 -56 -136 -162 -155 -186 -39 -50 -211 -264 -215 -268 -4 -4 -155
-192 -188 -235 -19 -25 -131 -185 -164 -235 -46 -70 -131 -221 -161 -285 -37
-77 -75 -163 -85 -190 -6 -16 -17 -43 -23 -60 -7 -16 -13 -32 -14 -35 -2 -11
-27 -86 -32 -100 -3 -8 -8 -24 -10 -34 -2 -10 -12 -53 -23 -95 -10 -42 -21
-94 -25 -116 -3 -23 -8 -52 -10 -65 -28 -137 -27 -633 0 -798 3 -15 7 -43 10
-62 3 -19 8 -53 11 -75 7 -44 62 -265 76 -305 3 -8 16 -44 28 -80 107 -313
338 -619 641 -850 71 -55 243 -170 253 -170 3 0 28 -14 56 -30 28 -17 57 -30
65 -30 8 0 15 -4 15 -10 0 -5 9 -10 20 -10 11 0 20 -4 20 -9 0 -5 10 -11 23
-14 12 -3 65 -22 117 -42 136 -53 311 -95 465 -112 98 -11 321 -5 411 11 94
16 212 54 270 87 20 11 36 14 39 9 7 -12 684 -14 686 -2 1 4 2 169 2 368 l2
361 32 40 c87 106 95 114 117 107 12 -4 23 -10 26 -14 6 -8 147 -68 230 -98
323 -115 754 -107 1080 20 102 40 294 138 310 159 3 3 15 12 28 18 25 13 25
14 118 90 120 97 289 289 335 380 8 14 16 28 19 31 25 25 117 225 148 320 25
78 49 173 57 220 2 19 9 62 14 95 9 58 7 350 -3 407 -2 16 -7 47 -11 70 -21
133 -75 291 -151 443 -114 230 -275 416 -509 590 -84 62 -342 193 -359 182 -1
-1 -9 3 -17 10 -8 6 -41 19 -74 28 -185 51 -307 68 -485 67 -64 0 -131 -3
-150 -5 -19 -3 -57 -9 -85 -12 -39 -6 -225 -51 -280 -69 -43 -13 -187 -78
-231 -102 l-48 -27 -22 26 c-46 54 -154 244 -312 547 -94 181 -107 205 -114
208 -5 2 -8 8 -8 13 0 10 -79 140 -90 149 -4 3 -11 12 -16 21 -35 62 -167 197
-241 247 -72 48 -156 87 -208 98 -11 2 -31 7 -45 10 -55 14 -246 13 -310 -1z
m2295 -1799 c49 -5 125 -22 155 -34 8 -3 17 -6 20 -7 40 -14 157 -69 184 -87
202 -132 334 -305 395 -518 12 -41 26 -86 30 -100 8 -28 7 -276 -2 -325 -31
-171 -136 -372 -254 -488 -118 -116 -282 -209 -428 -243 -117 -27 -345 -37
-345 -15 0 5 44 35 98 66 96 58 322 203 332 214 3 3 28 24 55 45 75 59 176
165 220 231 40 61 88 174 100 235 9 46 10 187 2 225 -16 76 -20 90 -39 134
-42 94 -123 196 -223 281 -36 31 -184 134 -205 143 -8 4 -28 16 -45 26 -32 21
-153 88 -275 154 -41 22 -77 42 -79 44 -9 7 6 12 54 18 28 4 51 8 52 9 4 3
152 -3 198 -8z"/>
<path d="M3470 4818 c-28 -10 -80 -62 -81 -81 0 -7 -3 -24 -5 -39 -7 -40 19
-91 59 -122 28 -22 45 -27 79 -25 80 5 129 51 135 128 5 52 -18 98 -61 126
-30 20 -91 26 -126 13z"/>
<path d="M3759 967 c-149 -63 -230 -177 -232 -327 -2 -96 2 -114 36 -180 138
-265 520 -262 650 4 34 69 48 162 34 226 -28 127 -97 216 -207 267 -81 38
-204 43 -281 10z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

@ -1,19 +0,0 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

@ -87,10 +87,8 @@ export async function recover(
useToken: false,
withCredentials: true,
});
console.log(recoverResponse);
return [recoverResponse];
} catch (nativeError) {
console.log(nativeError);
const [error] = parseAxiosError(nativeError);
return [null, `Не удалось восстановить пароль. ${error}`];

@ -6,6 +6,7 @@ type InfoProps = {
sx?: SxProps;
onClick?: any;
className?: string;
color?: string;
};
export default function Info({
@ -14,6 +15,7 @@ export default function Info({
sx,
onClick,
className,
color = "#7e2aea",
}: InfoProps) {
return (
<IconButton sx={sx} className={className} onClick={onClick}>
@ -26,21 +28,21 @@ export default function Info({
>
<path
d="M10 19C14.9706 19 19 14.9706 19 10C19 5.02944 14.9706 1 10 1C5.02944 1 1 5.02944 1 10C1 14.9706 5.02944 19 10 19Z"
stroke="#7E2AEA"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M9.25 9.25H10V14.5H10.75"
stroke="#7E2AEA"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M9.8125 7C10.4338 7 10.9375 6.49632 10.9375 5.875C10.9375 5.25368 10.4338 4.75 9.8125 4.75C9.19118 4.75 8.6875 5.25368 8.6875 5.875C8.6875 6.49632 9.19118 7 9.8125 7Z"
fill="#7E2AEA"
fill={color}
/>
</svg>
</IconButton>

@ -3,10 +3,11 @@ import { Box, useTheme } from "@mui/material";
import type { SxProps } from "@mui/material";
type InfoIconProps = {
color?: string;
sx?: SxProps;
};
export default function InfoIcon({ sx }: InfoIconProps) {
export default function InfoIcon({ sx, color = "#7e2aea" }: InfoIconProps) {
const theme = useTheme();
return (
@ -29,21 +30,21 @@ export default function InfoIcon({ sx }: InfoIconProps) {
>
<path
d="M12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21Z"
stroke={theme.palette.brightPurple.main}
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M11.25 11.25H12V16.5H12.75"
stroke={theme.palette.brightPurple.main}
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M11.8125 9C12.4338 9 12.9375 8.49632 12.9375 7.875C12.9375 7.25368 12.4338 6.75 11.8125 6.75C11.1912 6.75 10.6875 7.25368 10.6875 7.875C10.6875 8.49632 11.1912 9 11.8125 9Z"
fill={theme.palette.brightPurple.main}
fill={color}
/>
</svg>
</Box>

@ -1,7 +1,6 @@
import type { QuizQuestionBase, QuestionHint, PreviewRule } from "./shared";
export const UPLOAD_FILE_TYPES_MAP = {
all: "Все типы файлов",
picture: "Изображения",
video: "Видео",
audio: "Аудио",

@ -60,30 +60,31 @@ export default function ContactFormPage() {
<Box
sx={{
p: isTablet ? "0 0 150px 0" : "0",
mt: "67px",
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "10px",
m: "67px 0 41px 0",
}}
>
<Link
sx={{
fontSize: "16px",
lineHeight: "19px",
color: theme.palette.brightPurple.main,
textDecorationColor: theme.palette.brightPurple.main,
}}
>
Как собрать данные посетителя
</Link>{" "}
{/* <Popover>
<Info />
</Popover> */}
</Box>
{/*<Box*/}
{/* sx={{*/}
{/* display: "flex",*/}
{/* alignItems: "center",*/}
{/* gap: "10px",*/}
{/* m: "67px 0 41px 0",*/}
{/* }}*/}
{/*>*/}
{/* <Link*/}
{/* sx={{*/}
{/* fontSize: "16px",*/}
{/* lineHeight: "19px",*/}
{/* color: theme.palette.brightPurple.main,*/}
{/* textDecorationColor: theme.palette.brightPurple.main,*/}
{/* }}*/}
{/* >*/}
{/* Как собрать данные посетителя*/}
{/* </Link>{" "}*/}
{/* /!* <Popover>*/}
{/* <Info />*/}
{/* </Popover> *!/*/}
{/*</Box>*/}
{!quiz?.config.formContact.fields.name.used &&
!quiz?.config.formContact.fields.email.used &&
!quiz?.config.formContact.fields.phone.used &&

@ -21,6 +21,7 @@ interface Props {
placeholderHelp: string;
placeholderField: string;
closeDrawer: () => void;
noinputs: boolean;
}
export default function NewFieldParent({
@ -30,6 +31,7 @@ export default function NewFieldParent({
placeholderField,
outerContainerSx: sx,
children,
noinputs = false,
}: Props) {
const quiz = useCurrentQuiz();
@ -44,65 +46,71 @@ export default function NewFieldParent({
gap: "20px",
}}
>
<Box sx={{ display: "flex", flexDirection: "column", gap: "15px" }}>
<Typography>Подсказка</Typography>
<CustomTextField
onChange={({ target }) => {
updateQuiz(quiz.id, (quiz) => {
quiz.config.formContact.fields[defaultValue].text = target.value;
});
}}
value={quiz.config.formContact.fields[defaultValue].text}
placeholder={placeholderHelp}
text={""}
/>
</Box>
<Box sx={{ display: "flex", flexDirection: "column", gap: "15px" }}>
<Typography>Подсказка внутри поля</Typography>
<CustomTextField
onChange={({ target }) => {
updateQuiz(quiz.id, (quiz) => {
quiz.config.formContact.fields[defaultValue].innerText =
target.value;
});
}}
value={quiz.config.formContact.fields[defaultValue].innerText}
placeholder={placeholderField}
text={""}
/>
</Box>
<Box sx={{ display: "flex", flexDirection: "column", gap: "15px" }}>
<Typography>Ключ</Typography>
<TextField
value={quiz.config.formContact.fields[defaultValue].key}
onChange={({ target }) => {
updateQuiz(quiz.id, (quiz) => {
quiz.config.formContact.fields[defaultValue].key = target.value;
});
}}
placeholder="text"
sx={{
"& .css-1d3z3hw-MuiOutlinedInput-notchedOutline": {
border: "none",
},
"& .MuiInputBase-root": {
height: "48px",
borderRadius: "10px",
backgroundColor: "#EEE4FC",
},
}}
/>
<CustomCheckbox
checked={quiz.config.formContact.fields[defaultValue].required}
handleChange={({ target }) => {
updateQuiz(quiz.id, (quiz) => {
quiz.config.formContact.fields[defaultValue].required =
target.checked;
});
}}
label={"Обязательно к заполнению"}
/>
</Box>
{!noinputs && (
<>
<Box sx={{ display: "flex", flexDirection: "column", gap: "15px" }}>
<Typography>Название поля</Typography>
<CustomTextField
onChange={({ target }) => {
updateQuiz(quiz.id, (quiz) => {
quiz.config.formContact.fields[defaultValue].text =
target.value;
});
}}
value={quiz.config.formContact.fields[defaultValue].text}
placeholder={placeholderHelp}
text={""}
/>
</Box>
<Box sx={{ display: "flex", flexDirection: "column", gap: "15px" }}>
<Typography>Подсказка внутри поля</Typography>
<CustomTextField
onChange={({ target }) => {
updateQuiz(quiz.id, (quiz) => {
quiz.config.formContact.fields[defaultValue].innerText =
target.value;
});
}}
value={quiz.config.formContact.fields[defaultValue].innerText}
placeholder={placeholderField}
text={""}
/>
</Box>
</>
)}
{/*<Box sx={{ display: "flex", flexDirection: "column", gap: "15px" }}>*/}
{/* <Typography>Ключ</Typography>*/}
{/* <TextField*/}
{/* value={quiz.config.formContact.fields[defaultValue].key}*/}
{/* onChange={({ target }) => {*/}
{/* updateQuiz(quiz.id, (quiz) => {*/}
{/* quiz.config.formContact.fields[defaultValue].key = target.value;*/}
{/* });*/}
{/* }}*/}
{/* placeholder="text"*/}
{/* sx={{*/}
{/* "& .css-1d3z3hw-MuiOutlinedInput-notchedOutline": {*/}
{/* border: "none",*/}
{/* },*/}
{/* "& .MuiInputBase-root": {*/}
{/* height: "48px",*/}
{/* borderRadius: "10px",*/}
{/* backgroundColor: "#EEE4FC",*/}
{/* },*/}
{/* }}*/}
{/* />*/}
{/* <CustomCheckbox*/}
{/* checked={quiz.config.formContact.fields[defaultValue].required}*/}
{/* handleChange={({ target }) => {*/}
{/* updateQuiz(quiz.id, (quiz) => {*/}
{/* quiz.config.formContact.fields[defaultValue].required =*/}
{/* target.checked;*/}
{/* });*/}
{/* }}*/}
{/* label={"Обязательно к заполнению"}*/}
{/* />*/}
{/*</Box>*/}
{/* <Box>
<Typography>Запрашивать на</Typography>
<CustomCheckbox label={'Шаг 1'}/>

@ -25,6 +25,7 @@ export default function SwitchNewField({
closeDrawer={closeDrawer}
placeholderHelp={"Введите имя"}
placeholderField={"Дмитрий"}
noinputs={true}
defaultValue={"name"}
/>
);
@ -34,6 +35,7 @@ export default function SwitchNewField({
closeDrawer={closeDrawer}
placeholderHelp={"Введите Email"}
placeholderField={"mail@example.ru"}
noinputs={true}
defaultValue={"email"}
/>
);
@ -43,6 +45,7 @@ export default function SwitchNewField({
closeDrawer={closeDrawer}
placeholderHelp={"Введите номер"}
placeholderField={"+7 900 000 00 00"}
noinputs={true}
defaultValue={"phone"}
>
{/* <FormControlLabel
@ -69,6 +72,7 @@ export default function SwitchNewField({
closeDrawer={closeDrawer}
placeholderHelp={"Введите фамилию"}
placeholderField={"Иванов"}
noinputs={false}
defaultValue={"text"}
/>
);
@ -78,6 +82,7 @@ export default function SwitchNewField({
closeDrawer={closeDrawer}
placeholderHelp={"Введите адрес"}
placeholderField={"Москва, Лаврушинский пер., 10"}
noinputs={true}
defaultValue={"address"}
/>
);

@ -128,7 +128,11 @@ export default function WindowNewField({ drawerState, closeDrawer }: Props) {
{buttonSetting.flatMap((e, i) =>
drawerState.field === e.value || drawerState.field === "all" ? (
<MiniButtonSetting
disabled={quiz.config.formContact.fields[e.value].used}
disabled={
drawerState.field === e.value
? false
: quiz.config.formContact.fields[e.value].used
}
key={i}
onClick={() => {
SSHC(e.value);
@ -139,9 +143,13 @@ export default function WindowNewField({ drawerState, closeDrawer }: Props) {
? theme.palette.brightPurple.main
: "transparent",
color:
switchState === e.value && drawerState.field === "all"
(switchState === e.value && drawerState.field === "all") ||
drawerState.field === e.value
? "#ffffff"
: theme.palette.grey3.main,
"&:hover": {
background: switchState === e.value ? "#581CA7" : "#f5f5f5",
},
}}
>
{e.icon}

@ -62,7 +62,6 @@ export const DesignPage = () => {
setCurrentStep(index);
};
console.log(quiz);
if (quiz === undefined)
return (
<Skeleton sx={{ width: "100vw", height: "100vh", transform: "none" }} />

@ -43,12 +43,13 @@ import VidjetInstall from "./VidjetInstall";
import InstallQzCode from "./InstallQzCode";
import { incrementCurrentStep, updateQuiz } from "@root/quizes/actions";
import { useCurrentQuiz } from "@root/quizes/hooks";
import { useDomainDefine } from "@utils/hooks/useDomainDefine";
type BackgroundType = "text" | "video";
export default function InstallQuiz() {
const quiz = useCurrentQuiz();
const { isTestServer } = useDomainDefine();
const [display, setDisplay] = React.useState("1");
const handleChange = (event: SelectChangeEvent) => {
setDisplay(event.target.value);
@ -194,8 +195,9 @@ export default function InstallQuiz() {
<TextField
disabled
id={"inputLinkone"}
value="https://s.hbpn.link/"
// value="https://pena.com/"
value={
isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"
}
sx={{
"& .css-1d3z3hw-MuiOutlinedInput-notchedOutline": {
border: "none",

@ -109,7 +109,9 @@ export default function Counter() {
>
760
</Typography>
<Typography>готовых шаблонов для разных ниш</Typography>
<Typography>
готовых шаблонов для разных ниш <br></br> (в разработке)
</Typography>
</Box>
</Box>
</Box>

@ -121,7 +121,12 @@ export default function Component() {
>
<Button
variant="text"
sx={{ fontSize: "16px", fontWeight: 500, color: "white" }}
sx={{
fontSize: "16px",
fontWeight: 500,
color: "white",
justifyContent: "start",
}}
href={"https://hub.pena.digital/docs/oferta"}
target="_blank"
>
@ -129,7 +134,12 @@ export default function Component() {
</Button>
<Button
variant="text"
sx={{ fontSize: "16px", fontWeight: 500, color: "white" }}
sx={{
fontSize: "16px",
fontWeight: 500,
color: "white",
justifyContent: "start",
}}
href={"https://hub.pena.digital/docs/privacy"}
target="_blank"
>

@ -63,8 +63,13 @@ export default function Component() {
<Typography variant="body1">
Помогаем посетителю оставить заявку.{" "}
<br style={{ display: isTablet ? "flex" : "none" }} /> Готовые
шаблоны квизов с легкой установкой на любой сайт и социальные сети
шаблоны квизов с легкой установкой на любой сайт
</Typography>
{/* <Typography variant="body1">
Помогаем посетителю оставить заявку.{" "}
<br style={{ display: isTablet ? "flex" : "none" }} /> Готовые
шаблоны квизов с легкой установкой на любой сайт и социальные сети
</Typography> */}
</Box>
<Button

@ -168,7 +168,10 @@ export default function HowItWorks() {
}}
>
<Icon21 />
<Typography fontSize="18px"> на сайте</Typography>
<Typography fontSize="18px">
{" "}
на сайте (в разработке)
</Typography>
</Box>
<Box
sx={{
@ -210,7 +213,9 @@ export default function HowItWorks() {
}}
>
<Icon1 />
<Typography fontSize="18px">А/Б тестирование</Typography>
<Typography fontSize="18px">
А/Б тестирование (в разработке)
</Typography>
</Box>
</Box>
</Box>
@ -458,7 +463,10 @@ export default function HowItWorks() {
}}
>
<Icon15 />
<Typography fontSize="18px"> калькулятор цен</Typography>
<Typography fontSize="18px">
{" "}
калькулятор цен<br></br>(в разработке)
</Typography>
</Box>
</Box>
<Box
@ -479,7 +487,7 @@ export default function HowItWorks() {
}}
>
<Icon16 />
<Typography fontSize="18px"> скидки</Typography>
<Typography fontSize="18px"> скидки (в разработке)</Typography>
</Box>
</Box>
</Box>
@ -610,7 +618,10 @@ export default function HowItWorks() {
}}
>
<Icon19 />
<Typography fontSize="18px"> интеграция с CRM</Typography>
<Typography fontSize="18px">
{" "}
интеграция с CRM<br></br>(в разработке)
</Typography>
</Box>
</Box>
<Box

@ -284,7 +284,7 @@ export default function Component() {
>
Конверсию можно увеличить, добавив тающую скидку, консультанта
с подсказками или бонус, который пользователь получит в конце
квиза
квиза<br></br>(в разработке)
</Typography>
</Box>
</BoxFich>
@ -321,6 +321,7 @@ export default function Component() {
>
Аналитика
</Typography>
<Typography>(в разработке)</Typography>
</Box>
<Box maxWidth={"230px"}>
<Typography
@ -355,7 +356,7 @@ export default function Component() {
lineHeight: "28.44px",
}}
>
Расширенеие настройки дизайна
Расширенные настройки дизайна
</Typography>
</Box>
<Box maxWidth={"230px"}>
@ -440,6 +441,7 @@ export default function Component() {
>
А/Б тестирование
</Typography>
<Typography>(в разработке)</Typography>
</Box>
<Box maxWidth={"230px"}>
<Typography
@ -489,6 +491,7 @@ export default function Component() {
>
Интерактивные тесты
</Typography>
<Typography>(в разработке)</Typography>
</Box>
<Box maxWidth={"234px"}>
<Typography

@ -56,7 +56,6 @@ export default function ButtonsOptionsAndPict({
openBranchingPage,
setOpenBranchingPage,
}: Props) {
console.log(setOpenBranchingPage);
const [buttonHover, setButtonHover] = useState<string>("");
const [openedReallyChangingModal, setOpenedReallyChangingModal] =
useState<boolean>(false);

@ -98,19 +98,20 @@ export default function QuestionsPage({
position: "relative",
}}
>
<IconButton
onClick={() => {
createUntypedQuestion(quiz.backendId);
}}
sx={{
position: "fixed",
bottom: "103px",
}}
data-cy="create-question"
>
<AddPlus />
</IconButton>
{!openBranchingPage && (
<IconButton
onClick={() => {
createUntypedQuestion(quiz.backendId);
}}
sx={{
position: "fixed",
bottom: "103px",
}}
data-cy="create-question"
>
<AddPlus />
</IconButton>
)}
<Box sx={{ display: "flex", gap: "8px", marginLeft: "auto" }}>
<Button
variant="outlined"

@ -19,7 +19,6 @@ export default function AnswerOptions({
openBranchingPage,
setOpenBranchingPage,
}: Props) {
console.log(setOpenBranchingPage);
const onClickAddAnAnswer = useAddAnswer();
const [switchState, setSwitchState] = useState("setting");
const theme = useTheme();

@ -54,10 +54,8 @@ export const EmailSettingsCard = ({ quizExpand }: Props) => {
? isMobile
? "10px 10px 0 10px"
: "20px 20px 0 20px"
: isMobile
? "10px"
: "20px",
flexDirection: isMobile ? "column" : null,
: "20px",
// flexDirection: isMobile ? "column" : null,
justifyContent: "space-between",
minHeight: "40px",
}}
@ -75,7 +73,7 @@ export const EmailSettingsCard = ({ quizExpand }: Props) => {
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
width: isMobile ? "100%" : "auto",
width: "auto",
position: "relative",
}}
>
@ -156,100 +154,100 @@ export const EmailSettingsCard = ({ quizExpand }: Props) => {
},
}}
/>
<Typography
sx={{
color: "#4D4D4D",
m: "20px 0 14px 0",
fontSize: "18px",
fontWeight: 500,
}}
>
E-mail ответа
</Typography>
<TextField
value={quiz.config.resultInfo.reply}
placeholder={"noreplay@example.ru"}
onChange={({ target }: { target: HTMLInputElement }) => {
updateQuiz(quiz.id, (quiz) => {
quiz.config.resultInfo.reply = target.value;
});
}}
sx={{
margin: isMobile ? "10px 0" : 0,
width: "100%",
"& .MuiInputBase-root": {
color: "#000000",
backgroundColor: expand
? theme.palette.background.default
: "transparent",
height: "48px",
borderRadius: "10px",
".MuiOutlinedInput-notchedOutline": {
borderWidth: "1px !important",
border: expand ? "none" : null,
},
"& .MuiInputBase-input::placeholder": {
color: "#4D4D4D",
opacity: 0.8,
},
},
}}
inputProps={{
sx: {
fontSize: "18px",
lineHeight: "21px",
py: 0,
paddingLeft: "18px",
},
}}
/>
<Typography
sx={{
color: "#4D4D4D",
m: "20px 0 14px 0",
fontSize: "18px",
fontWeight: 500,
}}
>
Имя отправителя
</Typography>
<TextField
value={quiz.config.resultInfo.replname}
placeholder={"Название компании"}
onChange={({ target }: { target: HTMLInputElement }) => {
updateQuiz(quiz.id, (quiz) => {
quiz.config.resultInfo.replname = target.value;
});
}}
sx={{
margin: isMobile ? "10px 0" : 0,
width: "100%",
"& .MuiInputBase-root": {
color: "#000000",
backgroundColor: expand
? theme.palette.background.default
: "transparent",
height: "48px",
borderRadius: "10px",
".MuiOutlinedInput-notchedOutline": {
borderWidth: "1px !important",
border: expand ? "none" : null,
},
"& .MuiInputBase-input::placeholder": {
color: "#4D4D4D",
opacity: 0.8,
},
},
}}
inputProps={{
sx: {
fontSize: "18px",
lineHeight: "21px",
py: 0,
paddingLeft: "18px",
},
}}
/>
{/*<Typography*/}
{/* sx={{*/}
{/* color: "#4D4D4D",*/}
{/* m: "20px 0 14px 0",*/}
{/* fontSize: "18px",*/}
{/* fontWeight: 500,*/}
{/* }}*/}
{/*>*/}
{/* E-mail ответа*/}
{/*</Typography>*/}
{/*<TextField*/}
{/* value={quiz.config.resultInfo.reply}*/}
{/* placeholder={"noreplay@example.ru"}*/}
{/* onChange={({ target }: { target: HTMLInputElement }) => {*/}
{/* updateQuiz(quiz.id, (quiz) => {*/}
{/* quiz.config.resultInfo.reply = target.value;*/}
{/* });*/}
{/* }}*/}
{/* sx={{*/}
{/* margin: isMobile ? "10px 0" : 0,*/}
{/* width: "100%",*/}
{/* "& .MuiInputBase-root": {*/}
{/* color: "#000000",*/}
{/* backgroundColor: expand*/}
{/* ? theme.palette.background.default*/}
{/* : "transparent",*/}
{/* height: "48px",*/}
{/* borderRadius: "10px",*/}
{/* ".MuiOutlinedInput-notchedOutline": {*/}
{/* borderWidth: "1px !important",*/}
{/* border: expand ? "none" : null,*/}
{/* },*/}
{/* "& .MuiInputBase-input::placeholder": {*/}
{/* color: "#4D4D4D",*/}
{/* opacity: 0.8,*/}
{/* },*/}
{/* },*/}
{/* }}*/}
{/* inputProps={{*/}
{/* sx: {*/}
{/* fontSize: "18px",*/}
{/* lineHeight: "21px",*/}
{/* py: 0,*/}
{/* paddingLeft: "18px",*/}
{/* },*/}
{/* }}*/}
{/*/>*/}
{/*<Typography*/}
{/* sx={{*/}
{/* color: "#4D4D4D",*/}
{/* m: "20px 0 14px 0",*/}
{/* fontSize: "18px",*/}
{/* fontWeight: 500,*/}
{/* }}*/}
{/*>*/}
{/* Имя отправителя*/}
{/*</Typography>*/}
{/*<TextField*/}
{/* value={quiz.config.resultInfo.replname}*/}
{/* placeholder={"Название компании"}*/}
{/* onChange={({ target }: { target: HTMLInputElement }) => {*/}
{/* updateQuiz(quiz.id, (quiz) => {*/}
{/* quiz.config.resultInfo.replname = target.value;*/}
{/* });*/}
{/* }}*/}
{/* sx={{*/}
{/* margin: isMobile ? "10px 0" : 0,*/}
{/* width: "100%",*/}
{/* "& .MuiInputBase-root": {*/}
{/* color: "#000000",*/}
{/* backgroundColor: expand*/}
{/* ? theme.palette.background.default*/}
{/* : "transparent",*/}
{/* height: "48px",*/}
{/* borderRadius: "10px",*/}
{/* ".MuiOutlinedInput-notchedOutline": {*/}
{/* borderWidth: "1px !important",*/}
{/* border: expand ? "none" : null,*/}
{/* },*/}
{/* "& .MuiInputBase-input::placeholder": {*/}
{/* color: "#4D4D4D",*/}
{/* opacity: 0.8,*/}
{/* },*/}
{/* },*/}
{/* }}*/}
{/* inputProps={{*/}
{/* sx: {*/}
{/* fontSize: "18px",*/}
{/* lineHeight: "21px",*/}
{/* py: 0,*/}
{/* paddingLeft: "18px",*/}
{/* },*/}
{/* }}*/}
{/*/>*/}
</Box>
)}
</Paper>

@ -173,7 +173,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
display: expand ? "none" : "flex",
alignItems: "center",
padding: isMobile ? "10px" : "0 20px 20px",
flexDirection: isMobile ? "column" : null,
// flexDirection: isMobile ? "column" : null,
justifyContent: "space-between",
minHeight: "40px",
}}
@ -229,7 +229,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
width: isMobile ? "100%" : "auto",
width: "auto",
position: "relative",
}}
>

@ -128,8 +128,8 @@ export const WhenCard = ({ quizExpand }: Props) => {
sx={{
display: "flex",
alignItems: "center",
padding: isMobile ? "10px" : "20px",
flexDirection: isMobile ? "column" : null,
padding: "20px",
//flexDirection: isMobile ? "column" : null,
justifyContent: "space-between",
minHeight: "40px",
}}
@ -147,7 +147,7 @@ export const WhenCard = ({ quizExpand }: Props) => {
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
width: isMobile ? "100%" : "auto",
width: "auto",
position: "relative",
}}
>

@ -19,7 +19,6 @@ export const Tabs = ({
TabIndicatorProps={{ sx: { display: "none" } }}
value={selectedItem}
onChange={(event, newValue: "count" | "day") => {
console.log(newValue);
setSelectedItem(newValue);
}}
variant="scrollable"

@ -1,5 +1,5 @@
import { Link, useLocation, useNavigate } from "react-router-dom";
import { makeRequest } from "@frontend/kitui";
import { makeRequest, useToken } from "@frontend/kitui";
import { useEffect, useState } from "react";
import type { GetTariffsResponse } from "@model/tariff";
import { clearAuthToken } from "@frontend/kitui";
@ -24,7 +24,7 @@ import { createTariffElements } from "./tariffsUtils/createTariffElements";
import HeaderFull from "@ui_kit/Header/HeaderFull";
import Logotip from "../../pages/Landing/images/icons/QuizLogo";
import { LogoutButton } from "@ui_kit/LogoutButton";
import { clearUserData } from "@root/user";
import { clearUserData, useUserStore } from "@root/user";
import ArrowLeft from "@icons/questionsPage/arrowLeft";
import { currencyFormatter } from "./tariffsUtils/currencyFormatter";
@ -38,7 +38,9 @@ const StepperText: Record<string, string> = {
function TariffPage() {
const theme = useTheme();
const token = useToken();
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const userId = useUserStore((state) => state.userId);
const location = useLocation();
const navigate = useNavigate();
@ -69,12 +71,10 @@ function TariffPage() {
process.env.REACT_APP_DOMAIN +
`/strator/tariff?page=${page}&limit=100`,
});
console.log(page);
tariffsList.push(...tariffsResult.tariffs);
}
console.log("это то что мы отдаём перед концом", tariffsList);
return tariffsList;
};
@ -90,7 +90,6 @@ function TariffPage() {
url: process.env.REACT_APP_DOMAIN + "/price/discounts",
});
setUser(user);
console.log("это то что мы получили в самом конце", tariffsList);
setTariffs(tariffsList);
setDiscounts(discounts.Discounts);
let c = currencyFormatter.format(Number(user.wallet.cash) / 100);
@ -133,18 +132,16 @@ function TariffPage() {
var link = document.createElement("a");
link.href =
process.env.REACT_APP_DOMAIN +
`/payment?action=squizpay&dif=${
"https://hub.pena.digital" +
`/quizpayment?action=squizpay&dif=${
(price - Number(user.wallet.cash)) * 100
}`;
}&data=${token}&userid=${userId}
`;
document.body.appendChild(link);
// link.click();
link.click();
}
};
const purchasesAmount = user?.wallet.purchasesAmount ?? 0;
const isUserNko = user?.status === "nko";
console.log(tariffs);
const filteredTariffs = tariffs.filter((tariff) => {
return (
tariff.privileges[0].serviceKey === "squiz" &&
@ -153,7 +150,6 @@ function TariffPage() {
tariff.privileges[0]?.type === selectedItem
);
});
console.log(filteredTariffs);
async function handleLogoutClick() {
const [, logoutError] = await logout();

@ -11,6 +11,7 @@ export function calcIndividualTariffPrices(
priceBeforeDiscounts: number;
priceAfterDiscounts: number;
} {
console.log("MAGIC", purchasesAmount);
const priceBeforeDiscounts =
tariff.price ||
tariff.privileges.reduce(
@ -46,6 +47,7 @@ export function calcIndividualTariffPrices(
priceAfterDiscounts *= findDiscountFactor(cart.appliedLoyaltyDiscount);
priceAfterDiscounts *= findDiscountFactor(cart.appliedCartPurchasesDiscount);
console.log("OLOLOLOLO", cart, discounts, purchasesAmount, tariff);
// cart.allAppliedDiscounts.forEach((discount) => {
// priceAfterDiscounts *= findDiscountFactor(discount)
// })

@ -16,11 +16,12 @@ export const createTariffElements = (
const tariffElements = filteredTariffs
.filter((tariff) => tariff.privileges.length > 0)
.map((tariff, index) => {
console.log("USSSSSES", user);
const { priceBeforeDiscounts, priceAfterDiscounts } =
calcIndividualTariffPrices(
tariff,
discounts,
user.purchasesAmount,
user.wallet.spent,
[],
user.isUserNko,
);
@ -46,7 +47,7 @@ export const createTariffElements = (
buttonProps={{
text: "Выбрать",
onClick: () =>
onclick({ id: tariff._id, price: priceBeforeDiscounts / 100 }),
onclick({ id: tariff._id, price: priceAfterDiscounts / 100 }),
}}
headerText={tariff.name}
text={tariff.privileges.map((p) => `${p.name} - ${p.amount}`)}

@ -111,10 +111,7 @@ export const Footer = ({
}, [question, answers]);
const showResult = (nextQuestion: QuizQuestionResult) => {
console.log("Следующий результат будет вот такой", nextQuestion);
const isEmpty = checkEmptyData({ resultData: nextQuestion });
console.log("isEmpty", isEmpty);
if (nextQuestion) {
if (nextQuestion && quiz?.config.resultInfo.showResultForm === "before") {
if (isEmpty) {
@ -134,8 +131,6 @@ export const Footer = ({
};
const getNextQuestionId = () => {
console.log("net");
console.log(question);
let readyBeNextQuestion = "";
//вопрос обязателен, анализируем ответ и условия ветвления
@ -182,7 +177,6 @@ export const Footer = ({
if (!question.required) {
//вопрос не обязателен и не нашли совпадений между ответами и условиями ветвления
console.log("вопрос не обязателен ищем дальше");
const defaultQ = question.content.rule.default;
if (defaultQ.length > 1 && defaultQ !== " ") return defaultQ;
//Вопросы типа страница, ползунок, своё поле для ввода и дата не могут иметь больше 1 ребёнка. Пользователь не может настроить там дефолт
@ -197,13 +191,7 @@ export const Footer = ({
return question.content.rule.children[0];
}
//ничё не нашли, ищем резулт
console.log("ничё не нашли, ищем резулт ");
return questions.find((q) => {
console.log('q.type === "result"', q.type === "result");
console.log(
"q.content.rule.parentId === question.content.id",
q.content.rule.parentId === question.content.id,
);
return (
q.type === "result" && q.content.rule.parentId === question.content.id
);
@ -237,7 +225,6 @@ export const Footer = ({
};
const followNextStep = () => {
console.log(" Я понимаю что нахожусь в линейном опроснике" + linear);
if (linear) {
setStepNumber((q) => q + 1);
const questionIndex = questions.findIndex(({ id }) => id === question.id);
@ -253,10 +240,8 @@ export const Footer = ({
const nextQuestionId = getNextQuestionId();
console.log(nextQuestionId);
if (nextQuestionId) {
const nextQuestion = getQuestionByContentId(nextQuestionId);
console.log(nextQuestion);
if (nextQuestion?.type && nextQuestion.type === "result") {
showResult(nextQuestion);

@ -66,7 +66,6 @@ export const ResultForm = ({
};
if (resultQuestion === undefined) return <></>;
console.log("Я форма показа резултата и он такой ", resultQuestion);
return (
<Box
sx={{

@ -30,8 +30,6 @@ export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
if (!quiz) return null;
console.log(quiz);
const handleCopyNumber = () => {
navigator.clipboard.writeText(quiz.config.info.phonenumber);
};
@ -85,8 +83,6 @@ export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
) : null
) : null;
console.log(background);
return (
<Paper
className="quiz-preview-draghandle"

@ -102,6 +102,16 @@ export const Emoji = ({ currentQuestion }: EmojiProps) => {
color: theme.palette.text.primary,
display: "flex",
gap: "10px",
alignItems:
variant.answer.length <= 60 ? "center" : "flex-start",
position: "relative",
height: "80px",
"& .MuiFormControlLabel-label": {
wordBreak: "break-word",
height: variant.answer.length <= 60 ? undefined : "60px",
overflow: "auto",
paddingLeft: "45px",
},
}}
value={index}
onClick={(event) => {

@ -4,6 +4,8 @@ import {
ButtonBase,
useTheme,
IconButton,
Modal,
useMediaQuery,
} from "@mui/material";
import { useQuizViewStore, updateAnswer } from "@root/quizView";
import { UPLOAD_FILE_TYPES_MAP } from "@ui_kit/QuizPreview/QuizPreviewQuestionTypes/File";
@ -15,16 +17,108 @@ import type { ChangeEvent } from "react";
import type { QuizQuestionFile } from "../../../model/questionTypes/file";
import type { DragEvent } from "react";
import type { UploadFileType } from "@model/questionTypes/file";
import { useState } from "react";
import Info from "@icons/Info";
type FileProps = {
currentQuestion: QuizQuestionFile;
};
const CurrentModal = ({
status,
}: {
status:
| "errorType"
| "errorSize"
| "picture"
| "video"
| "audio"
| "document"
| "";
}) => {
switch (status) {
case "errorType":
return (
<>
<Typography>Выбран некорректный тип файла</Typography>
</>
);
case "errorSize":
return (
<>
<Typography>
Файл слишком большой. Максимальный размер 50 МБ
</Typography>
</>
);
default:
return (
<>
<Typography>Допустимые расширения файлов:</Typography>
<Typography>
{ACCEPT_SEND_FILE_TYPES_MAP[status].join(" ")}
</Typography>
</>
);
}
};
const ACCEPT_SEND_FILE_TYPES_MAP = {
picture: [
".jpeg",
".jpg",
".png",
".ico",
".gif",
".tiff",
".webp",
".eps",
".svg",
],
video: [
".mp4",
".mov",
".wmv",
".avi",
".avchd",
".flv",
".f4v",
".swf",
".mkv",
".webm",
".mpeg-2",
],
audio: [
".aac",
".aiff",
".dsd",
".flac",
".mp3",
".mqa",
".ogg",
".wav",
".wma",
],
document: [
".doc",
".docx",
".dotx",
".rtf",
".odt",
".pdf",
".txt",
".xls",
".ppt",
".xlsx",
".pptx",
".pages",
],
};
export const UPLOAD_FILE_DESCRIPTIONS_MAP: Record<
UploadFileType,
{ title: string; description: string }
> = {
all: { title: "Добавить файл", description: "Принимает любые файлы" },
picture: {
title: "Добавить изображение",
description: "Принимает изображения",
@ -39,154 +133,216 @@ export const UPLOAD_FILE_DESCRIPTIONS_MAP: Record<
export const File = ({ currentQuestion }: FileProps) => {
const { answers } = useQuizViewStore();
const [statusModal, setStatusModal] = useState<
"errorType" | "errorSize" | "picture" | "video" | "audio" | "document" | ""
>("");
const answer = answers.find(
({ questionId }) => questionId === currentQuestion.content.id,
)?.answer as string;
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(500));
const uploadFile = ({ target }: ChangeEvent<HTMLInputElement>) => {
const file = target.files?.[0];
if (file) {
updateAnswer(
currentQuestion.content.id,
`${file.name}|${URL.createObjectURL(file)}`,
);
if (file.size <= 52428800) {
//проверяем на соответствие
console.log(file.name.toLowerCase());
if (
ACCEPT_SEND_FILE_TYPES_MAP[currentQuestion.content.type].find(
(ednding) => {
console.log(ednding);
console.log(file.name.toLowerCase().endsWith(ednding));
return file.name.toLowerCase().endsWith(ednding);
},
)
) {
updateAnswer(
currentQuestion.content.id,
`${file.name}|${URL.createObjectURL(file)}`,
);
} else {
//неподходящий формат
setStatusModal("errorType");
}
} else {
setStatusModal("errorSize");
}
}
};
return (
<Box>
<Typography variant="h5" color={theme.palette.text.primary}>
{currentQuestion.title}
</Typography>
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
marginTop: "20px",
maxWidth: answer?.split("|")[0] ? "640px" : "550px",
}}
>
{answer?.split("|")[0] && (
<Box sx={{ display: "flex", alignItems: "center", gap: "15px" }}>
<Typography color={theme.palette.text.primary}>
Вы загрузили:
</Typography>
<Box
sx={{
padding: "5px 5px 5px 16px",
backgroundColor: theme.palette.primary.main,
borderRadius: "8px",
color: "#FFFFFF",
display: "flex",
alignItems: "center",
overflow: "hidden",
gap: "15px",
}}
>
<Typography
sx={{
whiteSpace: "nowrap",
textOverflow: "ellipsis",
overflow: "hidden",
}}
>
{answer?.split("|")[0]}
<>
<Box>
<Typography variant="h5" color={theme.palette.text.primary}>
{currentQuestion.title}
</Typography>
<Box
sx={{
display: "flex",
flexDirection: "column",
width: "100%",
marginTop: "20px",
maxWidth: answer?.split("|")[0] ? "640px" : "600px",
}}
>
{answer?.split("|")[0] && (
<Box sx={{ display: "flex", alignItems: "center", gap: "15px" }}>
<Typography color={theme.palette.text.primary}>
Вы загрузили:
</Typography>
<IconButton
sx={{ p: 0 }}
onClick={() => {
updateAnswer(currentQuestion.content.id, "");
<Box
sx={{
padding: "5px 5px 5px 16px",
backgroundColor: theme.palette.primary.main,
borderRadius: "8px",
color: "#FFFFFF",
display: "flex",
alignItems: "center",
overflow: "hidden",
gap: "15px",
}}
>
<CloseBold />
</IconButton>
</Box>
</Box>
)}
{!answer?.split("|")[0] && (
<ButtonBase component="label" sx={{ justifyContent: "flex-start" }}>
<input
onChange={uploadFile}
hidden
accept={UPLOAD_FILE_TYPES_MAP[currentQuestion.content.type]}
multiple
type="file"
/>
<Box
onDragOver={(event: DragEvent<HTMLDivElement>) =>
event.preventDefault()
}
sx={{
width: "100%",
height: "120px",
display: "flex",
gap: "50px",
justifyContent: "flex-start",
alignItems: "center",
padding: "33px 44px 33px 55px",
backgroundColor: theme.palette.background.default,
border: `1px solid #9A9AAF`,
// border: `1px solid ${theme.palette.grey2.main}`,
borderRadius: "8px",
}}
>
<UploadIcon />
<Box>
<Typography
sx={{
color: "#9A9AAF",
// color: theme.palette.grey2.main,
fontWeight: 500,
whiteSpace: "nowrap",
textOverflow: "ellipsis",
overflow: "hidden",
}}
>
{
UPLOAD_FILE_DESCRIPTIONS_MAP[currentQuestion.content.type]
.title
}
{answer?.split("|")[0]}
</Typography>
<Typography
sx={{
color: "#9A9AAF",
// color: theme.palette.grey2.main,
fontSize: "16px",
lineHeight: "19px",
<IconButton
sx={{ p: 0 }}
onClick={() => {
updateAnswer(currentQuestion.content.id, "");
}}
>
{
UPLOAD_FILE_DESCRIPTIONS_MAP[currentQuestion.content.type]
.description
}
</Typography>
<CloseBold />
</IconButton>
</Box>
</Box>
</ButtonBase>
)}
{answer && currentQuestion.content.type === "picture" && (
<img
src={answer.split("|")[1]}
alt=""
style={{
marginTop: "15px",
maxWidth: "300px",
maxHeight: "300px",
}}
/>
)}
{answer && currentQuestion.content.type === "video" && (
<video
src={answer.split("|")[1]}
style={{
marginTop: "15px",
maxWidth: "300px",
maxHeight: "300px",
objectFit: "cover",
}}
/>
)}
)}
{!answer?.split("|")[0] && (
<Box
sx={{
display: "flex",
alignItems: "center",
}}
>
<ButtonBase
component="label"
sx={{ justifyContent: "flex-start" }}
>
<input
onChange={uploadFile}
hidden
accept={ACCEPT_SEND_FILE_TYPES_MAP[
currentQuestion.content.type
].join(",")}
multiple
type="file"
/>
<Box
onDragOver={(event: DragEvent<HTMLDivElement>) =>
event.preventDefault()
}
sx={{
width: "100%",
height: isMobile ? undefined : "120px",
display: "flex",
gap: "50px",
justifyContent: "flex-start",
alignItems: "center",
padding: "33px 44px 33px 55px",
backgroundColor: theme.palette.background.default,
border: `1px solid #9A9AAF`,
// border: `1px solid ${theme.palette.grey2.main}`,
borderRadius: "8px",
}}
>
<UploadIcon />
<Box>
<Typography
sx={{
color: "#9A9AAF",
// color: theme.palette.grey2.main,
fontWeight: 500,
}}
>
{
UPLOAD_FILE_DESCRIPTIONS_MAP[
currentQuestion.content.type
].title
}
</Typography>
<Typography
sx={{
color: "#9A9AAF",
// color: theme.palette.grey2.main,
fontSize: "16px",
lineHeight: "19px",
}}
>
{
UPLOAD_FILE_DESCRIPTIONS_MAP[
currentQuestion.content.type
].description
}
</Typography>
</Box>
</Box>
</ButtonBase>
<Info
sx={{ width: "40px", height: "40px" }}
color={theme.palette.primary.main}
onClick={() => setStatusModal(currentQuestion.content.type)}
/>
</Box>
)}
{answer && currentQuestion.content.type === "picture" && (
<img
src={answer.split("|")[1]}
alt=""
style={{
marginTop: "15px",
maxWidth: "300px",
maxHeight: "300px",
}}
/>
)}
{answer && currentQuestion.content.type === "video" && (
<video
src={answer.split("|")[1]}
style={{
marginTop: "15px",
maxWidth: "300px",
maxHeight: "300px",
objectFit: "cover",
}}
/>
)}
</Box>
</Box>
</Box>
<Modal open={Boolean(statusModal)} onClose={() => setStatusModal("")}>
<Box
sx={{
position: "absolute" as "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: isMobile ? 300 : 400,
bgcolor: "background.paper",
borderRadius: 3,
boxShadow: 24,
p: 4,
}}
>
<CurrentModal status={statusModal} />
</Box>
</Modal>
</>
);
};

@ -72,7 +72,6 @@ export const Images = ({ currentQuestion }: ImagesProps) => {
}}
onClick={(event) => {
event.preventDefault();
updateAnswer(
currentQuestion.content.id,
currentQuestion.content.variants[index].id,
@ -107,8 +106,16 @@ export const Images = ({ currentQuestion }: ImagesProps) => {
marginTop: "10px",
marginLeft: 0,
padding: "10px",
display: "flex",
alignItems:
variant.answer.length <= 60 ? "center" : "flex-start",
position: "relative",
height: "80px",
"& .MuiFormControlLabel-label": {
wordBreak: "break-word",
height: variant.answer.length <= 60 ? undefined : "60px",
overflow: "auto",
paddingLeft: "45px",
},
}}
value={index}

@ -163,6 +163,8 @@ const VariantItem = ({
? "white"
: theme.palette.background.default,
display: "flex",
alignItems: variant.answer.length <= 60 ? "center" : "flex-start",
position: "relative",
maxWidth: "685px",
maxHeight: "85px",
justifyContent: "space-between",
@ -172,6 +174,8 @@ const VariantItem = ({
},
"& .MuiFormControlLabel-label": {
wordBreak: "break-word",
height: variant.answer.length <= 60 ? undefined : "60px",
overflow: "auto",
},
}}
value={index}

@ -88,9 +88,16 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
? theme.palette.primary.main
: "#9A9AAF",
display: "flex",
alignItems:
variant.answer.length <= 60 ? "center" : "flex-start",
position: "relative",
height: "80px",
margin: isMobile ? 0 : undefined,
"& .MuiFormControlLabel-label": {
wordBreak: "break-word",
height: variant.answer.length <= 60 ? undefined : "60px",
overflow: "auto",
paddingLeft: "45px",
},
}}
value={index}
@ -108,6 +115,7 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
}}
control={
<Radio
sx={{ position: "absolute" }}
checkedIcon={
<RadioCheck color={theme.palette.primary.main} />
}

@ -81,7 +81,6 @@ export default function RecoverPassword() {
setAuthToken("");
};
}, []);
console.log(tokenUser);
function handleClose() {
setIsDialogOpen(false);

@ -82,7 +82,7 @@ export default function MyQuizzesFull({
quiz.name = QuizgenegationName({ quiz });
});
}
return (
<QuizCard
key={quiz.id}

@ -14,10 +14,11 @@ import {
Popover,
} from "@mui/material";
import { deleteQuiz, setEditQuizId } from "@root/quizes/actions";
import { useNavigate } from "react-router-dom";
import { Link, useNavigate } from "react-router-dom";
import { inCart } from "../../pages/Tariffs/Tariffs";
import { makeRequest } from "@frontend/kitui";
import { enqueueSnackbar } from "notistack";
import { useDomainDefine } from "@utils/hooks/useDomainDefine";
interface Props {
quiz: Quiz;
@ -37,7 +38,7 @@ export default function QuizCard({
const navigate = useNavigate();
const [subMenuOpen, setSubMenuOpen] = useState<boolean>(false);
const subMenuRef = useRef<HTMLButtonElement | null>(null);
const { isTestServer } = useDomainDefine();
function handleEditClick() {
setEditQuizId(quiz.backendId);
navigate("/edit");
@ -108,8 +109,25 @@ export default function QuizCard({
}}
>
<LinkIcon bgcolor="#EEE4FC" color={theme.palette.brightPurple.main} />
<Typography color={theme.palette.grey3.main}>
быстрая ссылка ...
<Typography
color={theme.palette.grey3.main}
sx={{
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
maxWidth: "300px",
}}
component={Link}
target="_blank"
to={
isTestServer
? "https://s.hbpn.link/" + quiz.qid
: "https://hbpn.link/" + quiz.qid
}
>
{isTestServer
? `https://s.hbpn.link/${quiz.qid}`
: `https://hbpn.link/${quiz.qid}`}
</Typography>
</Box>
<Box

@ -22,6 +22,7 @@ import { questionApi } from "@api/question";
import { createResult, setQuestions } from "@root/questions/actions";
import { toggleQuizPreview } from "@root/quizPreview";
import VisibilityIcon from "@mui/icons-material/Visibility";
import { useDomainDefine } from "@utils/hooks/useDomainDefine";
interface Props {
sidebar: boolean;
@ -37,6 +38,7 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
const { questions } = useQuestionsStore();
const { editQuizId } = useQuizStore();
const currentStep = useQuizStore((state) => state.currentStep);
const { isTestServer } = useDomainDefine();
useEffect(() => {
const getData = async () => {
@ -56,7 +58,6 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
)
) {
createResult(quiz?.backendId, "line");
console.log("Я не нашёл линейный резулт и собираюсь создать новый");
}
}
};
@ -106,7 +107,6 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
useEffect(() => {
if (mainBlock.current) observer.current.observe(mainBlock.current);
}, [mainBlock, observer]);
console.log(widthMain);
if (!quizConfig) return <></>;
return (
@ -207,9 +207,15 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
fontSize: "14px",
}}
target="_blank"
to={"https://s.hbpn.link/" + quiz.qid}
to={
isTestServer
? "https://s.hbpn.link/" + quiz.qid
: "https://hbpn.link/" + quiz.qid
}
>
https://s.hbpn.link/{quiz.qid}
{isTestServer
? `https://s.hbpn.link/${quiz.qid}`
: `https://hbpn.link/${quiz.qid}`}
</Box>
) : (
<Box
@ -228,7 +234,11 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
borderRadius: "8px",
}}
target="_blank"
to={"https://s.hbpn.link/" + quiz.qid}
to={
isTestServer
? "https://s.hbpn.link/" + quiz.qid
: "https://hbpn.link/" + quiz.qid
}
>
<LinkSimple />
</Box>
@ -251,7 +261,11 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
borderRadius: "8px",
}}
target="_blank"
to={"https://s.hbpn.link/" + quiz.qid}
to={
isTestServer
? "https://s.hbpn.link/" + quiz.qid
: "https://hbpn.link/" + quiz.qid
}
>
<LinkSimple />
</Box>

@ -109,7 +109,7 @@ export default function EditPage({
const isConditionMet =
[1].includes(currentStep) && quizConfig.type !== "form";
console.log(quiz);
console.log("quiz", quiz);
return (
<>
<Box

@ -93,6 +93,16 @@ export default function Emoji({ question }: Props) {
display: "flex",
gap: "10px",
background: theme.palette.background.default,
alignItems:
variant.answer.length <= 60 ? "center" : "flex-start",
position: "relative",
height: "80px",
"& .MuiFormControlLabel-label": {
wordBreak: "break-word",
height: variant.answer.length <= 60 ? undefined : "60px",
overflow: "auto",
paddingLeft: "45px",
},
}}
control={
<Radio

@ -71,6 +71,7 @@ export default function Images({ question, widthPreview }: Props) {
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "flex-end",
borderRadius: "8px",
overflow: "hidden",
border: "1px solid",
@ -78,6 +79,7 @@ export default function Images({ question, widthPreview }: Props) {
? theme.palette.primary.main
: "#E3E3E3",
maxWidth: "300px",
minHeight: "250px",
maxHeight: "340px",
}}
>
@ -99,8 +101,11 @@ export default function Images({ question, widthPreview }: Props) {
<Box
sx={{
display: "flex",
alignItems: "center",
alignItems:
variant.answer.length <= 60 ? "center" : "flex-start",
justifyContent: "space-between",
overflow: "auto",
height: "80px",
gap: 2,
p: 1,
}}

@ -83,9 +83,17 @@ export default function Variant({ question }: Props) {
: theme.palette.background.default,
width: "100%",
margin: 0,
// "& .MuiFormControlLabel-label": {
// overflow: "hidden",
// }
display: "flex",
alignItems:
variant.answer.length <= 60 ? "center" : "flex-start",
position: "relative",
height: "80px",
"& .MuiFormControlLabel-label": {
wordBreak: "break-word",
height: variant.answer.length <= 60 ? undefined : "55px",
overflow: "auto",
paddingLeft: "45px",
},
}}
control={
question.content.multi ? (

@ -109,7 +109,17 @@ export default function Varimg({ question, widthPreview }: Props) {
backgroundColor: mode[quiz.config.theme]
? "white"
: theme.palette.background.default,
/*display: "flex",*/
display: "flex",
alignItems:
variant.answer.length <= 60 ? "center" : "flex-start",
position: "relative",
height: "80px",
"& .MuiFormControlLabel-label": {
wordBreak: "break-word",
height: variant.answer.length <= 60 ? undefined : "60px",
overflow: "auto",
paddingLeft: "45px",
},
}}
control={
<Radio

@ -1,10 +1,11 @@
import { Box, useTheme } from "@mui/material";
import { Box, SxProps, Theme, useTheme } from "@mui/material";
interface Props {
color?: string;
sx?: SxProps<Theme>;
}
export default function RadioCheck({ color = "#7E2AEA" }: Props) {
export default function RadioCheck({ color = "#7E2AEA", sx }: Props) {
const theme = useTheme();
return (
@ -15,6 +16,7 @@ export default function RadioCheck({ color = "#7E2AEA" }: Props) {
display: "flex",
alignItems: "center",
justifyContent: "center",
...sx,
}}
>
<svg

@ -1,6 +1,8 @@
import { Box, useTheme } from "@mui/material";
export default function RadioIcon() {
import { Box, SxProps, Theme, useTheme } from "@mui/material";
interface Props {
sx?: SxProps<Theme>;
}
export default function RadioIcon({ sx }: Props) {
const theme = useTheme();
return (
@ -11,6 +13,7 @@ export default function RadioIcon() {
display: "flex",
alignItems: "center",
justifyContent: "center",
...sx,
}}
>
<svg

@ -0,0 +1,13 @@
import { useEffect, useState } from "react";
export function useDomainDefine(): { isTestServer: boolean } {
const [isTestServer, setIsTestServer] = useState<boolean>(null);
useEffect(() => {
const host = window.location.hostname;
let isTest = host.includes("s");
setIsTestServer(isTest);
}, []);
return { isTestServer };
}

@ -16,21 +16,20 @@ const translateMessage: Record<string, string> = {
"user with this email or login is exist": "Пользователь уже существует",
"user with this login is exist":
"Пользователь с таким логином уже существует",
unauthorized: "Ссылка просрочена",
};
export const parseAxiosError = (nativeError: unknown): [string, number?] => {
console.log(nativeError);
const error = nativeError as AxiosError;
console.log(error);
console.log(error.response?.data);
if (error.response?.data) {
const serverError = error.response.data as ServerError;
let SEMessage;
if ("statusCode" in (error.response?.data as ServerError)) {
SEMessage = serverError?.message.toLowerCase() || "";
}
if ("error" in (error.response?.data as ServerError)) {
if (
"error" in (error.response?.data as ServerError) &&
!("statusCode" in (error.response?.data as ServerError))
) {
SEMessage = serverError?.error.toLowerCase() || "";
}
console.log(serverError);