diff --git a/package.json b/package.json index af12ffe6..844a197a 100755 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "@emotion/react": "^11.10.5", "@emotion/styled": "^11.10.5", "@frontend/kitui": "^1.0.82", - "@frontend/squzanswerer": "^1.0.38", + "@frontend/squzanswerer": "^1.0.41", "@mui/icons-material": "^5.10.14", "@mui/material": "^5.10.14", "@mui/x-charts": "^6.19.5", diff --git a/src/assets/icons/NumberThree.tsx b/src/assets/icons/NumberThree.tsx deleted file mode 100644 index f9978180..00000000 --- a/src/assets/icons/NumberThree.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Box } from "@mui/material"; - -interface Props { - color: string; -} - -export default function NumberThree({ color }: Props) { - return ( - - - - - - - ); -} diff --git a/src/assets/icons/NumberTwo.tsx b/src/assets/icons/NumberTwo.tsx deleted file mode 100644 index 85116206..00000000 --- a/src/assets/icons/NumberTwo.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Box } from "@mui/material"; - -interface Props { - color: string; -} - -export default function NumberTwo({ color }: Props) { - return ( - - - - - - - ); -} diff --git a/src/assets/icons/OneIconBorder.tsx b/src/assets/icons/OneIconBorder.tsx deleted file mode 100644 index e9ac34b4..00000000 --- a/src/assets/icons/OneIconBorder.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Box } from "@mui/material"; - -interface Props { - color: string; -} - -export default function OneIconBorder({ color }: Props) { - return ( - - - - - - - ); -} diff --git a/src/pages/InstallQuiz/InBodyInstall.tsx b/src/pages/InstallQuiz/InBodyInstall.tsx index abb494f7..68ae1bb7 100644 --- a/src/pages/InstallQuiz/InBodyInstall.tsx +++ b/src/pages/InstallQuiz/InBodyInstall.tsx @@ -1,21 +1,94 @@ -import { Box, Button, Link, Typography, useTheme } from "@mui/material"; -import InstallQzOnSiteParent from "./InstallQzOnSiteParent"; -import Dots from "../../assets/dots.png"; -import React from "react"; -import CustomTextField from "@ui_kit/CustomTextField"; +import { + Box, + Button, + Collapse, + Divider, + Typography, + useMediaQuery, + useTheme, +} from "@mui/material"; +import { useCurrentQuiz } from "@root/quizes/hooks"; +import CircleColorPicker from "@ui_kit/CircleColorPicker"; import CustomCheckbox from "@ui_kit/CustomCheckbox"; +import PenaTextField from "@ui_kit/PenaTextField"; +import { nanoid } from "nanoid"; +import { useState } from "react"; +import Dots from "../../assets/dots.png"; +import WidgetScript from "./QuizInstallationCard/WidgetScript"; +import { createContainerWidgetScriptText } from "./QuizInstallationCard/createWidgetScriptText"; -export default function InBodyInstall() { +interface Props { + step: 2 | 3; +} + +export default function InBodyInstall({ step }: Props) { const theme = useTheme(); + const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1065)); + const quiz = useCurrentQuiz(); + const [isAutoopenQuizSettingsOpen, setIsAutoopenQuizSettingsOpen] = + useState(false); + const [widgetWidth, setWidgetWidth] = useState(""); + const [widgetHeight, setWidgetHeight] = useState(""); + const [hideOnMobile, setHideOnMobile] = useState(false); + const [showButtonOnMobile, setShowButtonOnMobile] = useState(false); + const [rounded, setRounded] = useState(false); + const [withShadow, setWithShadow] = useState(false); + const [buttonFlash, setButtonFlash] = useState(false); + const [buttonText, setButtonText] = useState(""); + const [buttonBackgroundColor, setButtonBackgroundColor] = useState( + theme.palette.brightPurple.main, + ); + const [buttonTextColor, setButtonTextColor] = useState("#FFFFFF"); + const [autoShowQuiz, setAutoShowQuiz] = useState(false); + const [autoShowQuizTime, setAutoShowQuizTime] = useState(10); + const [openOnLeaveAttempt, setOpenOnLeaveAttempt] = useState(false); + + if (!quiz) return null; + + if (step === 3) { + const scriptText = createContainerWidgetScriptText({ + quizId: quiz.qid, + selector: `#pena-quiz-container-${nanoid(6)}`, + dimensions: + widgetWidth || widgetHeight + ? { + width: widgetWidth ? `${widgetWidth}px` : "100%", + height: widgetHeight ? `${widgetHeight}px` : "100%", + } + : undefined, + hideOnMobile: hideOnMobile || undefined, + showButtonOnMobile: showButtonOnMobile || undefined, + rounded: rounded || undefined, + withShadow: withShadow || undefined, + buttonFlash: buttonFlash || undefined, + buttonText: buttonText || undefined, + buttonBackgroundColor, + buttonTextColor, + autoShowQuizTime: autoShowQuiz ? autoShowQuizTime : undefined, + openOnLeaveAttempt: openOnLeaveAttempt || undefined, + }); + + return ; + } + return ( - - + + - + В мобильной версии будет показана кнопка, открывающая quiz в модальном окне - - Если quiz уже установлен на сайт, и вы что-то здесь изменили, код на - сайте нужно будет поменять. Настройки в этом конструкторе не - сохраняются. - - - 1. Задайте размеры (опционально) + + + 1. Задайте размеры (опционально) + Ширина (px) - - - Радиус (px) - - + setWidgetWidth(e.target.value)} + FormControlSx={{ maxWidth: "160px" }} + placeholder="auto" + /> Высота (px) - - - Отступ (px) - - + setWidgetHeight(e.target.value)} + FormControlSx={{ maxWidth: "160px" }} + placeholder="auto" + /> - - 2. Настройте кнопку для мобильной версии + + + 2. Настройте кнопку для мобильной версии + Цвет кнопки - - {" "} - + setButtonBackgroundColor(color)} + /> Цвет текста кнопки - - {" "} - + setButtonTextColor(color)} + /> - - - - - + setHideOnMobile(e.target.checked)} + /> + setRounded(e.target.checked)} + /> + setWithShadow(e.target.checked)} + /> + setButtonFlash(e.target.checked)} + /> + setShowButtonOnMobile(e.target.checked)} + /> Текст кнопки - - setButtonText(e.target.value)} + placeholder="Пройти тест" + FormControlSx={{ maxWidth: "360px" }} + /> + + + + setAutoShowQuiz(e.target.checked)} + /> + setOpenOnLeaveAttempt(e.target.checked)} + sx={{ + mt: "15px", + }} + /> + + + + + + Показывать через + + + setAutoShowQuizTime(parseInt(e.target.value)) + } + FormControlSx={{ + width: "90px", + }} + /> + + секунд + + + + + + - + ); } diff --git a/src/pages/InstallQuiz/QuizInstallationCard/InstallationStepButton.tsx b/src/pages/InstallQuiz/QuizInstallationCard/InstallationStepButton.tsx index 900f9833..20736b1d 100644 --- a/src/pages/InstallQuiz/QuizInstallationCard/InstallationStepButton.tsx +++ b/src/pages/InstallQuiz/QuizInstallationCard/InstallationStepButton.tsx @@ -17,7 +17,7 @@ export default function InstallationStepButton({ }: Props) { const theme = useTheme(); - const buttonColorByState: Record = { + const buttonColorByState: Record = { active: "#FC712F", done: theme.palette.brightPurple.main, inactive: theme.palette.grey2.main, @@ -28,13 +28,29 @@ export default function InstallationStepButton({ return ( diff --git a/src/pages/InstallQuiz/QuizInstallationCard/QuizInstallationCard.tsx b/src/pages/InstallQuiz/QuizInstallationCard/QuizInstallationCard.tsx index ea1648e9..498a5ab7 100644 --- a/src/pages/InstallQuiz/QuizInstallationCard/QuizInstallationCard.tsx +++ b/src/pages/InstallQuiz/QuizInstallationCard/QuizInstallationCard.tsx @@ -1,17 +1,8 @@ -import { - Box, - IconButton, - InputAdornment, - TextField as MuiTextField, - TextFieldProps, - Typography, - useMediaQuery, - useTheme, -} from "@mui/material"; +import { WidgetType } from "@frontend/squzanswerer"; +import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; import { useCurrentQuiz } from "@root/quizes/hooks"; -import { useDomainDefine } from "@utils/hooks/useDomainDefine"; -import { FC, useState } from "react"; -import CopyIcon from "../../../assets/icons/CopyIcon"; +import { useState } from "react"; +import InBodyInstall from "../InBodyInstall"; import InstallationStepButton from "./InstallationStepButton"; import WidgetTypeButton from "./WidgetTypeButton"; import BannerWidgetPreview from "./previewIcons/BannerWidgetPreview"; @@ -20,19 +11,20 @@ import ContainerWidgetPreview from "./previewIcons/ContainerWidgetPreview"; import PopupWidgetPreview from "./previewIcons/PopupWidgetPreview"; import SideWidgetPreview from "./previewIcons/SideWidgetPreview"; -const TextField = MuiTextField as unknown as FC; +type WidgetSetupSettings = { + step: 1 | 2 | 3; + widgetType: WidgetType; +}; export default function QuizInstallationCard() { const theme = useTheme(); - const quiz = useCurrentQuiz(); - const { isTestServer } = useDomainDefine(); - const [stepState, setStepState] = useState<1 | 2 | 3>(1); const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1065)); + const quiz = useCurrentQuiz(); + const [widgetSetupSettings, setWidgetSetupSettings] = + useState({ step: 1, widgetType: "container" }); if (!quiz) return null; - const scriptText = `
`; - return ( - - Установка quiz на сайте - - { - setStepState(1); + Установка quiz на сайте + - Способ установки - - { - setStepState(2); - }} - > - Настройка кнопки - - { - setStepState(3); - }} - > - Вставить код на сайт - - - - {stepState === 1 ? ( - <> - } - text1="По кнопке" - text2="Конструктор кнопки или собственная кнопка" - onClick={() => { - setStepState(2); - }} - /> - } - text1="Баннером" - text2="Сбоку или на всю ширину экрана" - onClick={() => { - setStepState(2); - }} - /> - } - text1="В тело сайта" - text2="Задайте свои размеры и встройте в сайт" - onClick={() => { - setStepState(2); - }} - /> - } - text1="Автооткрытие" - text2="Автооткрытие поп-ап на сайте" - onClick={() => { - setStepState(2); - }} - /> - } - text1="Виджет" - text2="Сбоку страницы, как консультант" - onClick={() => { - setStepState(2); - }} - /> - - ) : ( - <> - - { + setWidgetSetupSettings({ + step: 1, + widgetType: "container", + }); + }} + > + Способ установки + + {widgetSetupSettings.step !== 1 && ( + <> + { + setWidgetSetupSettings((prev) => ({ + ...prev, + step: 2, + })); }} > - 1. Код вставки quiz - - Установите код в то место, где должен быть quiz - - - - navigator.clipboard.writeText(scriptText) - } - > - - - - ), - }} - /> - - - - - Код нужно вставить один раз. Изменения в самом quiz будут - отображаться автоматически после сохранения. - - - Для установки размера добавьте в тег значения высоты и ширины, - например: - - - {`
`} -
-
- - )} + Настройка кнопки + + { + setWidgetSetupSettings((prev) => ({ + ...prev, + step: 3, + })); + }} + > + Вставить код на сайт + + + )} +
+ {widgetSetupSettings.step === 1 ? ( + + } + text1="По кнопке" + text2="Конструктор кнопки или собственная кнопка" + onClick={() => { + setWidgetSetupSettings({ + step: 2, + widgetType: "button", + }); + }} + /> + } + text1="Баннером" + text2="Сбоку или на всю ширину экрана" + onClick={() => { + setWidgetSetupSettings({ + step: 2, + widgetType: "banner", + }); + }} + /> + } + text1="В тело сайта" + text2="Задайте свои размеры и встройте в сайт" + onClick={() => { + setWidgetSetupSettings({ + step: 2, + widgetType: "container", + }); + }} + /> + } + text1="Автооткрытие" + text2="Автооткрытие поп-ап на сайте" + onClick={() => { + setWidgetSetupSettings({ + step: 2, + widgetType: "popup", + }); + }} + /> + } + text1="Виджет" + text2="Сбоку страницы, как консультант" + onClick={() => { + setWidgetSetupSettings({ + step: 2, + widgetType: "side", + }); + }} + /> + + ) : ( + <> + {widgetSetupSettings.widgetType === "container" && ( + + )} + + )} ); } diff --git a/src/pages/InstallQuiz/QuizInstallationCard/WidgetScript.tsx b/src/pages/InstallQuiz/QuizInstallationCard/WidgetScript.tsx new file mode 100644 index 00000000..3dc0171c --- /dev/null +++ b/src/pages/InstallQuiz/QuizInstallationCard/WidgetScript.tsx @@ -0,0 +1,66 @@ +import CopyIcon from "@icons/CopyIcon"; +import { + Box, + IconButton, + InputAdornment, + TextField as MuiTextField, + TextFieldProps, + Typography, + useTheme, +} from "@mui/material"; +import { FC } from "react"; + +const TextField = MuiTextField as unknown as FC; + +interface Props { + scriptText: string; +} + +export default function WidgetScript({ scriptText }: Props) { + const theme = useTheme(); + + return ( + + + Установите код в место, в котором должен быть квиз + + + { + navigator.clipboard.writeText(scriptText); + }} + edge="end" + sx={{ marginTop: "22px" }} + > + + + + ), + }} + /> + + ); +} diff --git a/src/pages/InstallQuiz/QuizInstallationCard/WidgetTypeButton.tsx b/src/pages/InstallQuiz/QuizInstallationCard/WidgetTypeButton.tsx index c0dffefc..5ff5c778 100644 --- a/src/pages/InstallQuiz/QuizInstallationCard/WidgetTypeButton.tsx +++ b/src/pages/InstallQuiz/QuizInstallationCard/WidgetTypeButton.tsx @@ -1,4 +1,11 @@ -import { Button, ButtonBase, Typography } from "@mui/material"; +import { + Box, + Button, + ButtonBase, + Typography, + useMediaQuery, + useTheme, +} from "@mui/material"; import { ReactNode } from "react"; interface Props { @@ -14,29 +21,43 @@ export default function WidgetTypeButton({ text1, text2, }: Props) { + const theme = useTheme(); + const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1065)); + return ( ); } diff --git a/src/pages/InstallQuiz/QuizInstallationCard/createWidgetScriptText.ts b/src/pages/InstallQuiz/QuizInstallationCard/createWidgetScriptText.ts new file mode 100644 index 00000000..60488144 --- /dev/null +++ b/src/pages/InstallQuiz/QuizInstallationCard/createWidgetScriptText.ts @@ -0,0 +1,55 @@ +import { + BannerWidgetParams, + ButtonWidgetFixedParams, + ButtonWidgetParams, + ContainerWidgetParams, + PopupWidgetParams, + SideWidgetParams, + WidgetType, +} from "@frontend/squzanswerer"; + +export function createContainerWidgetScriptText(params: ContainerWidgetParams) { + return `
+`; +} + +export function createButtonWidgetScriptText( + params: ButtonWidgetParams | ButtonWidgetFixedParams, +) { + const widgetClassName = + "fixedSide" in params ? "ButtonWidgetFixed" : "ButtonWidget"; + + return ``; +} + +export function createPopupWidgetScriptText(params: PopupWidgetParams) { + return ``; +} + +export function createSideWidgetScriptText(params: SideWidgetParams) { + return ``; +} + +export function createBannerWidgetScriptText(params: BannerWidgetParams) { + return ``; +} diff --git a/src/pages/InstallQuiz/QuizInstallationCard/previewIcons/WidgetPreviewContainer.tsx b/src/pages/InstallQuiz/QuizInstallationCard/previewIcons/WidgetPreviewContainer.tsx index 31ca9fa4..ecd9879e 100644 --- a/src/pages/InstallQuiz/QuizInstallationCard/previewIcons/WidgetPreviewContainer.tsx +++ b/src/pages/InstallQuiz/QuizInstallationCard/previewIcons/WidgetPreviewContainer.tsx @@ -1,4 +1,4 @@ -import { Box } from "@mui/material"; +import { Box, useMediaQuery, useTheme } from "@mui/material"; import { ReactNode } from "react"; interface Props { @@ -6,10 +6,13 @@ interface Props { } export default function WidgetPreviewContainer({ children }: Props) { + const theme = useTheme(); + const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1065)); + return ( - + {children} diff --git a/src/ui_kit/CircleColorPicker.tsx b/src/ui_kit/CircleColorPicker.tsx new file mode 100644 index 00000000..545aa40a --- /dev/null +++ b/src/ui_kit/CircleColorPicker.tsx @@ -0,0 +1,41 @@ +import { ButtonBase } from "@mui/material"; +import { startTransition, useRef } from "react"; + +interface Props { + color: string; + onChange: (color: string) => void; +} + +export default function CircleColorPicker({ color, onChange }: Props) { + const inputRef = useRef(null); + + return ( + inputRef.current?.click()} + sx={{ + aspectRatio: 1, + height: "22px", + width: "22px", + minWidth: "20px", + borderRadius: "50%", + backgroundColor: color, + border: "1px solid #4D4D4D", + }} + > + { + startTransition(() => { + onChange(e.target.value); + }); + }} + style={{ + opacity: 0, + cursor: "pointer", + }} + /> + + ); +} diff --git a/src/ui_kit/PenaTextField.tsx b/src/ui_kit/PenaTextField.tsx new file mode 100644 index 00000000..d7ed2eca --- /dev/null +++ b/src/ui_kit/PenaTextField.tsx @@ -0,0 +1,135 @@ +import { + FormControl, + InputLabel, + TextField as MuiTextField, + SxProps, + TextFieldProps, + Theme, + useMediaQuery, + useTheme, +} from "@mui/material"; +import { FC } from "react"; + +const TextField = MuiTextField as unknown as FC; + +interface Props { + id?: string; + label?: string; + labelSx?: SxProps; + bold?: boolean; + gap?: string; + backgroundColor?: string; + FormControlSx?: SxProps; + TextFieldSx?: SxProps; + placeholder?: TextFieldProps["placeholder"]; + value?: TextFieldProps["value"]; + helperText?: TextFieldProps["helperText"]; + error?: TextFieldProps["error"]; + type?: TextFieldProps["type"]; + onBlur?: TextFieldProps["onBlur"]; + onChange?: TextFieldProps["onChange"]; + fullWidth?: boolean; +} + +export default function PenaTextField({ + id, + label, + labelSx, + bold = false, + gap = "10px", + onChange, + error, + helperText, + onBlur, + placeholder, + type, + value, + backgroundColor, + FormControlSx, + TextFieldSx, + fullWidth = true, +}: Props) { + const theme = useTheme(); + const upMd = useMediaQuery(theme.breakpoints.up("md")); + + const labelFont = upMd + ? bold + ? theme.typography.p1 + : { ...theme.typography.body1, fontWeight: 500 } + : theme.typography.body2; + + const placeholderFont = upMd + ? undefined + : { fontWeight: 400, fontSize: "16px", lineHeight: "19px" }; + + return ( + + {label && ( + + {label} + + )} + + + ); +} diff --git a/yarn.lock b/yarn.lock index 51c9ffbe..d4330c50 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1527,10 +1527,10 @@ immer "^10.0.2" reconnecting-eventsource "^1.6.2" -"@frontend/squzanswerer@^1.0.38": - version "1.0.38" - resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/43/packages/npm/@frontend/squzanswerer/-/@frontend/squzanswerer-1.0.38.tgz#51f382368d73f9ad36c4f7f3357dedb32d5453e8" - integrity sha1-UfOCNo1z+a02xPfzNX3tsy1UU+g= +"@frontend/squzanswerer@^1.0.41": + version "1.0.41" + resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/43/packages/npm/@frontend/squzanswerer/-/@frontend/squzanswerer-1.0.41.tgz#d535b03c0a432a2c427c99083a6ec9b1e64e060e" + integrity sha1-1TWwPApDKixCfJkIOm7JseZOBg4= dependencies: bowser "1.9.4" country-flag-emoji-polyfill "^0.1.8"