Merge branch 'dev' into 'staging'
Dev See merge request frontend/squiz!339
This commit is contained in:
commit
8dbdcd5385
21621
package-lock.json
generated
Normal file
21621
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -55,6 +55,7 @@
|
||||
"react-scripts": "5.0.1",
|
||||
"react-slick": "^0.29.0",
|
||||
"slick-carousel": "^1.8.1",
|
||||
"swiper": "^11.1.4",
|
||||
"swr": "^2.2.4",
|
||||
"typescript": "^5.2.2",
|
||||
"use-debounce": "^9.0.4",
|
||||
@ -108,6 +109,7 @@
|
||||
"endOfLine": "auto",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"jsxSingleQuote": false
|
||||
"jsxSingleQuote": false,
|
||||
"singleAttributePerLine": true
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ export default function App() {
|
||||
});
|
||||
|
||||
useUserAccountFetcher<UserAccount>({
|
||||
url: `${process.env.REACT_APP_DOMAIN}/customer/account`,
|
||||
url: `${process.env.REACT_APP_DOMAIN}/customer/v1.0.0/account`,
|
||||
userId,
|
||||
onNewUserAccount: setCustomerAccount,
|
||||
onError: (error) => {
|
||||
|
@ -4,7 +4,7 @@ import { parseAxiosError } from "@utils/parse-error";
|
||||
|
||||
import type { UserAccount } from "@frontend/kitui";
|
||||
|
||||
const API_URL = `${process.env.REACT_APP_DOMAIN}/customer/cart`;
|
||||
const API_URL = `${process.env.REACT_APP_DOMAIN}/customer/v1.0.0/cart`;
|
||||
|
||||
const payCart = async (): Promise<[UserAccount | null, string?]> => {
|
||||
try {
|
||||
|
@ -13,7 +13,7 @@ export const getUser = async (): Promise<[UserAccount | null, string?]> => {
|
||||
try {
|
||||
const user = await makeRequest<never, UserAccount>({
|
||||
method: "GET",
|
||||
url: `${process.env.REACT_APP_DOMAIN}/customer/account`,
|
||||
url: `${process.env.REACT_APP_DOMAIN}/customer/v1.0.0/account`,
|
||||
});
|
||||
|
||||
return [user];
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 119 KiB |
Binary file not shown.
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 119 KiB |
22
src/assets/icons/questionsPage/AlignIcon.tsx
Normal file
22
src/assets/icons/questionsPage/AlignIcon.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { FC } from "react";
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
export const AlignIcon: FC = () => (
|
||||
<Box sx={{ width: `20px`, height: "20px" }}>
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M19 8.18348L11.8 8.22299V1M8.2 19V11.8165L1 11.7752"
|
||||
stroke="white"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</Box>
|
||||
);
|
35
src/assets/icons/questionsPage/EditIcon.tsx
Normal file
35
src/assets/icons/questionsPage/EditIcon.tsx
Normal file
File diff suppressed because one or more lines are too long
29
src/assets/icons/questionsPage/ExpandIcon.tsx
Normal file
29
src/assets/icons/questionsPage/ExpandIcon.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { FC } from "react";
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
export const ExpandIcon: FC = () => (
|
||||
<Box sx={{ width: `24px`, height: "24px" }}>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M18 6.58545L12.4984 2.17075C12.434 2.11677 12.3566 2.07382 12.271 2.04447C12.1853 2.01513 12.0931 2 12 2C11.9069 2 11.8147 2.01513 11.729 2.04447C11.6434 2.07382 11.566 2.11677 11.5016 2.17075L6 6.58545M18 17.4146L12.4984 21.8293C12.434 21.8832 12.3566 21.9262 12.271 21.9555C12.1853 21.9849 12.0931 22 12 22C11.9069 22 11.8147 21.9849 11.729 21.9555C11.6434 21.9262 11.566 21.8832 11.5016 21.8293L6 17.4146"
|
||||
stroke="white"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M11.9988 14.0054C13.0682 14.0054 13.9351 13.1385 13.9351 12.0691C13.9351 10.9997 13.0682 10.1328 11.9988 10.1328C10.9294 10.1328 10.0625 10.9997 10.0625 12.0691C10.0625 13.1385 10.9294 14.0054 11.9988 14.0054Z"
|
||||
stroke="white"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</Box>
|
||||
);
|
29
src/assets/icons/questionsPage/GrayPlus.tsx
Normal file
29
src/assets/icons/questionsPage/GrayPlus.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { FC } from "react";
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
export const GrayPlus: FC = () => (
|
||||
<Box sx={{ width: `32px` }}>
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M16.0029 1V31"
|
||||
stroke="#9A9AAF"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M31 15.9941L1 15.9941"
|
||||
stroke="#9A9AAF"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</Box>
|
||||
);
|
38
src/assets/icons/questionsPage/RoundedCheckedIcon.tsx
Normal file
38
src/assets/icons/questionsPage/RoundedCheckedIcon.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { FC } from "react";
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
export const RoundedCheckedIcon: FC = () => (
|
||||
<Box
|
||||
sx={{
|
||||
width: `26px`,
|
||||
height: "26px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
width="26"
|
||||
height="27"
|
||||
viewBox="0 0 26 27"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
x="0.5"
|
||||
y="1"
|
||||
width="25"
|
||||
height="25"
|
||||
rx="12.5"
|
||||
fill="#F2F3F7"
|
||||
stroke="#F2F3F7"
|
||||
/>
|
||||
<path
|
||||
d="M8 13.5L12.2857 17.5L18 10"
|
||||
stroke="#9A9AAF"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</Box>
|
||||
);
|
@ -15,12 +15,16 @@ import {
|
||||
Step,
|
||||
Tag,
|
||||
} from "@api/integration";
|
||||
import type { TagQuestionObject } from "@/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal"
|
||||
|
||||
type CustomRadioGroupProps = {
|
||||
type?: string;
|
||||
selectedValue: string | null;
|
||||
setSelectedValue: (value: string | null) => void;
|
||||
pipelineId?: number | null;
|
||||
items: TagQuestionObject[]
|
||||
tags: Tag[]
|
||||
setTags?: (setValueFunc: (value: Tag[]) => Tag[]) => void;
|
||||
};
|
||||
|
||||
const SIZE = 25;
|
||||
@ -30,6 +34,9 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
|
||||
selectedValue,
|
||||
setSelectedValue,
|
||||
pipelineId,
|
||||
items,
|
||||
tags = [],
|
||||
setTags,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
@ -40,13 +47,15 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
|
||||
);
|
||||
const [page, setPage] = useState(1);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [tags, setTags] = useState<Tag[]>([]);
|
||||
|
||||
const [steps, setSteps] = useState<Step[]>([]);
|
||||
const [pipelines, setPipelines] = useState<Pipeline[]>([]);
|
||||
const [hasMoreItems, setHasMoreItems] = useState(true);
|
||||
const boxRef = useRef(null);
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
console.log("применился хенделчейндж")
|
||||
console.log((event.target as HTMLInputElement).value)
|
||||
setSelectedValue((event.target as HTMLInputElement).value);
|
||||
setCurrentValue((event.target as HTMLInputElement).value);
|
||||
};
|
||||
@ -61,9 +70,12 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
|
||||
setPage((prevPage) => prevPage + 1);
|
||||
}
|
||||
};
|
||||
console.log(type)
|
||||
console.log(items)
|
||||
console.log(type === "typeQuestions" && items && items.length !== 0)
|
||||
|
||||
useEffect(() => {
|
||||
if (type === "typeTags" && hasMoreItems) {
|
||||
if (type === "typeTags" && hasMoreItems && setTags !== undefined) {
|
||||
setIsLoading(true);
|
||||
const pagination: PaginationRequest = {
|
||||
page: page,
|
||||
@ -71,7 +83,7 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
|
||||
};
|
||||
getTags(pagination).then(([response]) => {
|
||||
if (response && response.items !== null) {
|
||||
setTags((prevItems) => [...prevItems, ...response.items]);
|
||||
setTags((prevItems:Tag[]) => [...prevItems, ...response.items]);
|
||||
if (response.items.length < SIZE) {
|
||||
setHasMoreItems(false);
|
||||
}
|
||||
@ -118,9 +130,8 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
|
||||
if (type === "typeTags" && tags && tags.length !== 0) {
|
||||
return tags.map((item) => (
|
||||
<FormControlLabel
|
||||
key={item.ID}
|
||||
key={item.AmoID}
|
||||
sx={{
|
||||
color: "red",
|
||||
padding: "15px",
|
||||
borderBottom: `1px solid ${theme.palette.background.default}`,
|
||||
display: "flex",
|
||||
@ -128,11 +139,11 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
|
||||
borderRadius: "12px",
|
||||
margin: 0,
|
||||
backgroundColor:
|
||||
currentValue === item.Name
|
||||
currentValue === item.AmoID.toString()
|
||||
? theme.palette.background.default
|
||||
: theme.palette.common.white,
|
||||
}}
|
||||
value={item.Name}
|
||||
value={item.AmoID.toString()}
|
||||
control={
|
||||
<Radio
|
||||
checkedIcon={
|
||||
@ -232,6 +243,46 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
|
||||
/>
|
||||
));
|
||||
}
|
||||
if (type === "typeQuestions" && items && items.length !== 0) {
|
||||
return items.map(({ backendId, title }) => (
|
||||
<FormControlLabel
|
||||
key={backendId}
|
||||
sx={{
|
||||
color: "black",
|
||||
padding: "15px",
|
||||
borderBottom: `1px solid ${theme.palette.background.default}`,
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
borderRadius: "12px",
|
||||
margin: 0,
|
||||
backgroundColor:
|
||||
currentValue === backendId
|
||||
? theme.palette.background.default
|
||||
: theme.palette.common.white,
|
||||
"&.MuiFormControlLabel-root > .MuiTypography-root": {
|
||||
width: "200px",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis"
|
||||
}
|
||||
}}
|
||||
value={backendId}
|
||||
control={
|
||||
<Radio
|
||||
checkedIcon={
|
||||
<CheckboxIcon
|
||||
checked
|
||||
isRounded
|
||||
color={theme.palette.brightPurple.main}
|
||||
/>
|
||||
}
|
||||
icon={<CheckboxIcon isRounded />}
|
||||
/>
|
||||
}
|
||||
label={title}
|
||||
labelPlacement={"start"}
|
||||
/>
|
||||
));
|
||||
}
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
|
@ -1,16 +1,10 @@
|
||||
import { WidgetType } from "@frontend/squzanswerer";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { Box, Button, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import { useState } from "react";
|
||||
import InstallationStepButton from "./InstallationStepButton";
|
||||
import BannerWidgetSetup from "./WidgetSetupByType/BannerWidgetSetup/BannerWidgetSetup";
|
||||
import ButtonWidgetSetup from "./WidgetSetupByType/ButtonWidgetSetup";
|
||||
import ButtonWidgetSetup from "./WidgetSetupByType/ButtonWidgetSetup/ButtonWidgetSetup";
|
||||
import ContainerWidgetSetup from "./WidgetSetupByType/ContainerWidgetSetup";
|
||||
import PopupWidgetSetup from "./WidgetSetupByType/PopupWidgetSetup";
|
||||
import SideWidgetSetup from "./WidgetSetupByType/SideWidgetSetup/SideWidgetSetup";
|
||||
@ -30,16 +24,15 @@ export default function QuizInstallationCard() {
|
||||
const theme = useTheme();
|
||||
const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1065));
|
||||
const quiz = useCurrentQuiz();
|
||||
const [widgetSetupSettings, setWidgetSetupSettings] =
|
||||
useState<WidgetSetupSettings>({ step: 1, widgetType: "container" });
|
||||
const [widgetSetupSettings, setWidgetSetupSettings] = useState<WidgetSetupSettings>({
|
||||
step: 1,
|
||||
widgetType: "container",
|
||||
});
|
||||
|
||||
if (!quiz) return null;
|
||||
|
||||
const nextButton = (
|
||||
<Button
|
||||
onClick={() => setWidgetSetupSettings((prev) => ({ ...prev, step: 3 }))}
|
||||
variant="contained"
|
||||
>
|
||||
<Button onClick={() => setWidgetSetupSettings((prev) => ({ ...prev, step: 3 }))} variant="contained">
|
||||
Далее
|
||||
</Button>
|
||||
);
|
||||
@ -187,34 +180,19 @@ export default function QuizInstallationCard() {
|
||||
) : (
|
||||
<>
|
||||
{widgetSetupSettings.widgetType === "container" && (
|
||||
<ContainerWidgetSetup
|
||||
step={widgetSetupSettings.step}
|
||||
nextButton={nextButton}
|
||||
/>
|
||||
<ContainerWidgetSetup step={widgetSetupSettings.step} nextButton={nextButton} />
|
||||
)}
|
||||
{widgetSetupSettings.widgetType === "button" && (
|
||||
<ButtonWidgetSetup
|
||||
step={widgetSetupSettings.step}
|
||||
nextButton={nextButton}
|
||||
/>
|
||||
<ButtonWidgetSetup step={widgetSetupSettings.step} nextButton={nextButton} />
|
||||
)}
|
||||
{widgetSetupSettings.widgetType === "banner" && (
|
||||
<BannerWidgetSetup
|
||||
step={widgetSetupSettings.step}
|
||||
nextButton={nextButton}
|
||||
/>
|
||||
<BannerWidgetSetup step={widgetSetupSettings.step} nextButton={nextButton} />
|
||||
)}
|
||||
{widgetSetupSettings.widgetType === "popup" && (
|
||||
<PopupWidgetSetup
|
||||
step={widgetSetupSettings.step}
|
||||
nextButton={nextButton}
|
||||
/>
|
||||
<PopupWidgetSetup step={widgetSetupSettings.step} nextButton={nextButton} />
|
||||
)}
|
||||
{widgetSetupSettings.widgetType === "side" && (
|
||||
<SideWidgetSetup
|
||||
step={widgetSetupSettings.step}
|
||||
nextButton={nextButton}
|
||||
/>
|
||||
<SideWidgetSetup step={widgetSetupSettings.step} nextButton={nextButton} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
157
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/BannerWidgetSetup/BannerWidgetPreviewDesktop.tsx
Normal file
157
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/BannerWidgetSetup/BannerWidgetPreviewDesktop.tsx
Normal file
@ -0,0 +1,157 @@
|
||||
import TaskIcon from "@/ui_kit/TaskIcon";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import RunningStripe from "@ui_kit/RunningStripe";
|
||||
|
||||
interface Props {
|
||||
position: "topleft" | "topright" | "bottomleft" | "bottomright";
|
||||
bannerFullWidth: boolean;
|
||||
pulsation: boolean;
|
||||
rounded: boolean;
|
||||
withShadow: boolean;
|
||||
buttonFlash: boolean;
|
||||
buttonBackgroundColor: string;
|
||||
buttonTextColor: string;
|
||||
appealText: string;
|
||||
quizHeaderText: string;
|
||||
}
|
||||
|
||||
export default function BannerWidgetPreviewDesktop({
|
||||
bannerFullWidth,
|
||||
buttonBackgroundColor,
|
||||
buttonFlash,
|
||||
buttonTextColor,
|
||||
position,
|
||||
pulsation,
|
||||
rounded,
|
||||
withShadow,
|
||||
appealText,
|
||||
quizHeaderText,
|
||||
}: Props) {
|
||||
return (
|
||||
<Box
|
||||
sx={[
|
||||
{
|
||||
position: "absolute",
|
||||
width: "calc(196 / 520 * 100%)",
|
||||
height: "calc(30 / 262 * 100%)",
|
||||
transitionProperty: "width, height, top, left",
|
||||
transitionDuration: "0.5s",
|
||||
transitionTimingFunction: "ease",
|
||||
},
|
||||
position === "topleft" && {
|
||||
top: "calc(12.5 / 262 * 100%)",
|
||||
left: "calc(50.6 / 520 * 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 && {
|
||||
":before": {
|
||||
content: "''",
|
||||
position: "absolute",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
pointerEvents: "none",
|
||||
willChange: "box-shadow",
|
||||
borderRadius: "30px",
|
||||
animation: "pena-pulsation linear 5s infinite",
|
||||
"@keyframes pena-pulsation": {
|
||||
"0%": {
|
||||
boxShadow: "0 0 0 0 rgba(126, 42, 234, 0.5)",
|
||||
},
|
||||
"30%": {
|
||||
boxShadow: "0 0 0 15px rgba(0, 0, 0, 0)",
|
||||
},
|
||||
"100%": {
|
||||
boxShadow: "0 0 0 0 rgba(0, 0, 0, 0)",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
backgroundColor: buttonBackgroundColor,
|
||||
containerType: "size",
|
||||
gap: "calc(5 / 196 * 100%)",
|
||||
borderRadius: rounded && !bannerFullWidth ? "30px" : 0,
|
||||
boxShadow: withShadow ? "3px 6px 25px 3px rgba(25, 6, 50, 0.4), 0 3px 13px 0 rgba(35, 17, 58, 0.1)" : "none",
|
||||
}}
|
||||
>
|
||||
<TaskIcon
|
||||
sx={{
|
||||
width: "auto",
|
||||
height: "calc(18.57 / 29.5 * 100%)",
|
||||
ml: "calc(7.36 / 196 * 100%)",
|
||||
aspectRatio: 1,
|
||||
color: buttonTextColor,
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
color: buttonTextColor,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
fontSize="calc(6 / 29.5 * 100cqh)"
|
||||
lineHeight="120%"
|
||||
>
|
||||
{appealText || "Пройти тест"}
|
||||
</Typography>
|
||||
<Typography
|
||||
fontSize="calc(11 / 29.5 * 100cqh)"
|
||||
lineHeight="120%"
|
||||
>
|
||||
{quizHeaderText || "Заголовок теста"}
|
||||
</Typography>
|
||||
</Box>
|
||||
{buttonFlash && <RunningStripe />}
|
||||
</Box>
|
||||
<CloseIcon
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
color: "white",
|
||||
height: "calc(10 / 29.5 * 100%)",
|
||||
width: "auto",
|
||||
aspectRatio: 1,
|
||||
backgroundColor: rounded || bannerFullWidth ? "#581ca763" : undefined,
|
||||
borderRadius: "50%",
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
128
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/BannerWidgetSetup/BannerWidgetPreviewMobile.tsx
Normal file
128
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/BannerWidgetSetup/BannerWidgetPreviewMobile.tsx
Normal file
@ -0,0 +1,128 @@
|
||||
import TaskIcon from "@/ui_kit/TaskIcon";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import RunningStripe from "@ui_kit/RunningStripe";
|
||||
|
||||
interface Props {
|
||||
position: "topleft" | "topright" | "bottomleft" | "bottomright";
|
||||
pulsation: boolean;
|
||||
withShadow: boolean;
|
||||
buttonFlash: boolean;
|
||||
buttonBackgroundColor: string;
|
||||
buttonTextColor: string;
|
||||
appealText: string;
|
||||
quizHeaderText: string;
|
||||
}
|
||||
|
||||
export default function BannerWidgetPreviewMobile({
|
||||
buttonBackgroundColor,
|
||||
buttonFlash,
|
||||
buttonTextColor,
|
||||
position,
|
||||
pulsation,
|
||||
withShadow,
|
||||
appealText,
|
||||
quizHeaderText,
|
||||
}: Props) {
|
||||
return (
|
||||
<Box
|
||||
sx={[
|
||||
{
|
||||
position: "absolute",
|
||||
width: "calc(94 / 520 * 100%)",
|
||||
height: "calc(21 / 262 * 100%)",
|
||||
transitionProperty: "width, height, top, left",
|
||||
transitionDuration: "0.5s",
|
||||
transitionTimingFunction: "ease",
|
||||
},
|
||||
position.startsWith("top") && {
|
||||
top: "calc(66 / 262 * 100%)",
|
||||
left: "calc(422 / 520 * 100%)",
|
||||
},
|
||||
position.startsWith("bottom") && {
|
||||
top: "calc(208 / 262 * 100%)",
|
||||
left: "calc(422 / 520 * 100%)",
|
||||
},
|
||||
pulsation && {
|
||||
":before": {
|
||||
content: "''",
|
||||
position: "absolute",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
pointerEvents: "none",
|
||||
willChange: "box-shadow",
|
||||
borderRadius: "30px",
|
||||
animation: "pena-pulsation linear 5s infinite",
|
||||
"@keyframes pena-pulsation": {
|
||||
"0%": {
|
||||
boxShadow: "0 0 0 0 rgba(126, 42, 234, 0.5)",
|
||||
},
|
||||
"30%": {
|
||||
boxShadow: "0 0 0 15px rgba(0, 0, 0, 0)",
|
||||
},
|
||||
"100%": {
|
||||
boxShadow: "0 0 0 0 rgba(0, 0, 0, 0)",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
backgroundColor: buttonBackgroundColor,
|
||||
containerType: "size",
|
||||
gap: "calc(5 / 196 * 100%)",
|
||||
boxShadow: withShadow ? "3px 6px 25px 3px rgba(25, 6, 50, 0.4), 0 3px 13px 0 rgba(35, 17, 58, 0.1)" : "none",
|
||||
}}
|
||||
>
|
||||
<TaskIcon
|
||||
sx={{
|
||||
width: "auto",
|
||||
height: "calc(18.57 / 29.5 * 100%)",
|
||||
ml: "calc(7.36 / 196 * 100%)",
|
||||
aspectRatio: 1,
|
||||
color: buttonTextColor,
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
color: buttonTextColor,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
fontSize="calc(6 / 29.5 * 100cqh)"
|
||||
lineHeight="120%"
|
||||
>
|
||||
{appealText || "Пройти тест"}
|
||||
</Typography>
|
||||
<Typography
|
||||
fontSize="calc(11 / 29.5 * 100cqh)"
|
||||
lineHeight="120%"
|
||||
>
|
||||
{quizHeaderText || "Заголовок теста"}
|
||||
</Typography>
|
||||
</Box>
|
||||
{buttonFlash && <RunningStripe />}
|
||||
</Box>
|
||||
<CloseIcon
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
color: "white",
|
||||
height: "calc(8 / 29.5 * 100%)",
|
||||
width: "auto",
|
||||
aspectRatio: 1,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
208
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/BannerWidgetSetup/BannerWidgetSetup.tsx
208
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/BannerWidgetSetup/BannerWidgetSetup.tsx
@ -1,5 +1,4 @@
|
||||
import { BannerWidgetParams } from "@frontend/squzanswerer";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@ -19,12 +18,13 @@ import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||
import PenaTextField from "@ui_kit/PenaTextField";
|
||||
import RadioCheck from "@ui_kit/RadioCheck";
|
||||
import RadioIcon from "@ui_kit/RadioIcon";
|
||||
import RunningStripe from "@ui_kit/RunningStripe";
|
||||
import { ReactNode, useState } from "react";
|
||||
import fixedButtonWidgetPreview from "../../../../../assets/banner-widget-preview.png";
|
||||
import fixedBannerWidgetPreview from "../../../../../assets/banner-widget-preview.png";
|
||||
import WidgetScript from "../../WidgetScript";
|
||||
import { createBannerWidgetScriptText } from "../../createWidgetScriptText";
|
||||
import BannerWidgetPreviewIcon from "./BannerWidgetPreviewIcon";
|
||||
import { useWidgetUrl } from "../../useWidgetUrl";
|
||||
import BannerWidgetPreviewDesktop from "./BannerWidgetPreviewDesktop";
|
||||
import BannerWidgetPreviewMobile from "./BannerWidgetPreviewMobile";
|
||||
|
||||
interface Props {
|
||||
step: 2 | 3;
|
||||
@ -35,6 +35,7 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
||||
const theme = useTheme();
|
||||
const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1065));
|
||||
const quiz = useCurrentQuiz();
|
||||
const widgetUrl = useWidgetUrl();
|
||||
const [widgetWidth, setWidgetWidth] = useState<string>("");
|
||||
const [widgetHeight, setWidgetHeight] = useState<string>("");
|
||||
const [isAutoopenQuizSettingsOpen, setIsAutoopenQuizSettingsOpen] = useState<boolean>(false);
|
||||
@ -47,7 +48,7 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
||||
const [autoShowQuiz, setAutoShowQuiz] = useState<boolean>(false);
|
||||
const [autoShowQuizTime, setAutoShowQuizTime] = useState<number>(10);
|
||||
const [openOnLeaveAttempt, setOpenOnLeaveAttempt] = useState<boolean>(false);
|
||||
const [position, setPosition] = useState<BannerWidgetParams["position"]>("bottomleft");
|
||||
const [position, setPosition] = useState<BannerWidgetParams["position"]>("topleft");
|
||||
const [bannerFullWidth, setBannerFullWidth] = useState<boolean>(false);
|
||||
const [autoShowWidgetTime, setAutoShowWidgetTime] = useState<number>(10);
|
||||
const [appealText, setAppealText] = useState<string>("");
|
||||
@ -58,31 +59,34 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
||||
if (!quiz) return null;
|
||||
|
||||
if (step === 3) {
|
||||
const scriptText = createBannerWidgetScriptText({
|
||||
quizId: quiz.qid,
|
||||
position,
|
||||
hideOnMobile: hideOnMobile || undefined,
|
||||
rounded: bannerFullWidth ? undefined : rounded || undefined,
|
||||
withShadow: withShadow || undefined,
|
||||
buttonFlash: buttonFlash || undefined,
|
||||
buttonBackgroundColor,
|
||||
buttonTextColor,
|
||||
autoShowQuizTime: autoShowQuiz ? autoShowQuizTime : undefined,
|
||||
openOnLeaveAttempt: openOnLeaveAttempt || undefined,
|
||||
bannerFullWidth: bannerFullWidth || undefined,
|
||||
autoShowWidgetTime,
|
||||
appealText: appealText || undefined,
|
||||
quizHeaderText: quizHeaderText || undefined,
|
||||
pulsation: pulsation || undefined,
|
||||
fullScreen: fullScreen || undefined,
|
||||
dialogDimensions:
|
||||
!fullScreen && (widgetWidth || widgetHeight)
|
||||
? {
|
||||
width: widgetWidth ? `${widgetWidth}px` : "100%",
|
||||
height: widgetHeight ? `${widgetHeight}px` : "100%",
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
const scriptText = createBannerWidgetScriptText(
|
||||
{
|
||||
quizId: quiz.qid,
|
||||
position,
|
||||
hideOnMobile: hideOnMobile || undefined,
|
||||
rounded: bannerFullWidth ? undefined : rounded || undefined,
|
||||
withShadow: withShadow || undefined,
|
||||
buttonFlash: buttonFlash || undefined,
|
||||
buttonBackgroundColor,
|
||||
buttonTextColor,
|
||||
autoShowQuizTime: autoShowQuiz ? autoShowQuizTime : undefined,
|
||||
openOnLeaveAttempt: openOnLeaveAttempt || undefined,
|
||||
bannerFullWidth: bannerFullWidth || undefined,
|
||||
autoShowWidgetTime,
|
||||
appealText: appealText || undefined,
|
||||
quizHeaderText: quizHeaderText || undefined,
|
||||
pulsation: pulsation || undefined,
|
||||
fullScreen: fullScreen || undefined,
|
||||
dialogDimensions:
|
||||
!fullScreen && (widgetWidth || widgetHeight)
|
||||
? {
|
||||
width: widgetWidth ? `${widgetWidth}px` : "100%",
|
||||
height: widgetHeight ? `${widgetHeight}px` : "100%",
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
widgetUrl
|
||||
);
|
||||
|
||||
return <WidgetScript scriptText={scriptText} helperText="Установите код внутрь тэга head" />;
|
||||
}
|
||||
@ -109,129 +113,35 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={fixedButtonWidgetPreview}
|
||||
src={fixedBannerWidgetPreview}
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={[
|
||||
{
|
||||
position: "absolute",
|
||||
width: "calc(196 / 520 * 100%)",
|
||||
height: "calc(30 / 262 * 100%)",
|
||||
},
|
||||
position === "topleft" && {
|
||||
top: "calc(12.5 / 262 * 100%)",
|
||||
left: "calc(50.6 / 520 * 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 && {
|
||||
":before": {
|
||||
content: "''",
|
||||
position: "absolute",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
pointerEvents: "none",
|
||||
willChange: "box-shadow",
|
||||
borderRadius: "30px",
|
||||
animation: "pena-pulsation linear 5s infinite",
|
||||
"@keyframes pena-pulsation": {
|
||||
"0%": {
|
||||
boxShadow: "0 0 0 0 rgba(126, 42, 234, 0.5)",
|
||||
},
|
||||
"30%": {
|
||||
boxShadow: "0 0 0 15px rgba(0, 0, 0, 0)",
|
||||
},
|
||||
"100%": {
|
||||
boxShadow: "0 0 0 0 rgba(0, 0, 0, 0)",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "hidden",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
backgroundColor: theme.palette.brightPurple.main,
|
||||
containerType: "size",
|
||||
gap: "calc(5 / 196 * 100%)",
|
||||
borderRadius: rounded && !bannerFullWidth ? "30px" : 0,
|
||||
boxShadow: withShadow
|
||||
? "3px 6px 25px 3px rgba(25, 6, 50, 0.4), 0 3px 13px 0 rgba(35, 17, 58, 0.1)"
|
||||
: "none",
|
||||
}}
|
||||
>
|
||||
<BannerWidgetPreviewIcon
|
||||
sx={{
|
||||
height: "calc(18.57 / 29.5 * 100%)",
|
||||
width: "auto",
|
||||
aspectRatio: 1,
|
||||
ml: "calc(7.36 / 196 * 100%)",
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
color: "white",
|
||||
}}
|
||||
>
|
||||
<Typography fontSize="calc(6 / 29.5 * 100cqh)" lineHeight="120%">
|
||||
{appealText || "Пройти тест"}
|
||||
</Typography>
|
||||
<Typography fontSize="calc(11 / 29.5 * 100cqh)" lineHeight="120%">
|
||||
{quizHeaderText || "Заголовок теста"}
|
||||
</Typography>
|
||||
</Box>
|
||||
{buttonFlash && <RunningStripe />}
|
||||
</Box>
|
||||
<CloseIcon
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
color: "white",
|
||||
height: "calc(10 / 29.5 * 100%)",
|
||||
width: "auto",
|
||||
aspectRatio: 1,
|
||||
backgroundColor: rounded || bannerFullWidth ? "#581CA7" : undefined,
|
||||
borderRadius: "50%",
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<BannerWidgetPreviewDesktop
|
||||
appealText={appealText}
|
||||
quizHeaderText={quizHeaderText}
|
||||
position={position}
|
||||
pulsation={pulsation}
|
||||
withShadow={withShadow}
|
||||
buttonFlash={buttonFlash}
|
||||
bannerFullWidth={bannerFullWidth}
|
||||
buttonBackgroundColor={buttonBackgroundColor}
|
||||
buttonTextColor={buttonTextColor}
|
||||
rounded={rounded}
|
||||
/>
|
||||
<BannerWidgetPreviewMobile
|
||||
appealText={appealText}
|
||||
quizHeaderText={quizHeaderText}
|
||||
position={position}
|
||||
pulsation={pulsation}
|
||||
withShadow={withShadow}
|
||||
buttonFlash={buttonFlash}
|
||||
buttonBackgroundColor={buttonBackgroundColor}
|
||||
buttonTextColor={buttonTextColor}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
@ -327,9 +237,9 @@ export default function BannerWidgetSetup({ step, nextButton }: Props) {
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Цвет кнопки</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Цвет баннера</Typography>
|
||||
<CircleColorPicker color={buttonBackgroundColor} onChange={(color) => setButtonBackgroundColor(color)} />
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Цвет текста кнопки</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Цвет текста баннера</Typography>
|
||||
<CircleColorPicker color={buttonTextColor} onChange={(color) => setButtonTextColor(color)} />
|
||||
</Box>
|
||||
<CustomCheckbox
|
||||
|
73
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/ButtonWidgetSetup/ButtonWidgetPreviewDesktop.tsx
Normal file
73
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/ButtonWidgetSetup/ButtonWidgetPreviewDesktop.tsx
Normal file
@ -0,0 +1,73 @@
|
||||
import RunningStripe from "@/ui_kit/RunningStripe";
|
||||
import TaskIcon from "@/ui_kit/TaskIcon";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
|
||||
interface Props {
|
||||
buttonBackgroundColor: string;
|
||||
rounded: boolean;
|
||||
withShadow: boolean;
|
||||
fixedSide: "left" | "right";
|
||||
buttonTextColor: string;
|
||||
buttonText: string;
|
||||
buttonFlash: boolean;
|
||||
}
|
||||
|
||||
export default function ButtonWidgetPreviewDesktop({
|
||||
buttonBackgroundColor,
|
||||
buttonFlash,
|
||||
buttonText,
|
||||
buttonTextColor,
|
||||
fixedSide,
|
||||
rounded,
|
||||
withShadow,
|
||||
}: Props) {
|
||||
return (
|
||||
<Box
|
||||
sx={[
|
||||
{
|
||||
position: "absolute",
|
||||
height: "calc(20 / 262 * 100%)",
|
||||
px: "calc(1%)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
backgroundColor: buttonBackgroundColor,
|
||||
borderRadius: rounded ? "30px" : 0,
|
||||
transform: "rotate(-90deg)",
|
||||
transformOrigin: "left",
|
||||
transitionProperty: "width, height, top, left",
|
||||
transitionDuration: "0.5s",
|
||||
transitionTimingFunction: "ease",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
boxShadow: withShadow ? "2px 5px 20px 2px rgba(25, 6, 50, 0.4), 0 2px 10px 0 rgba(35, 17, 58, 0.1)" : "none",
|
||||
},
|
||||
fixedSide === "left" && {
|
||||
top: "calc(57%)",
|
||||
left: "calc(55 / 520 * 100%)",
|
||||
},
|
||||
fixedSide === "right" && {
|
||||
top: "calc(57%)",
|
||||
left: "calc(383 / 520 * 100%)",
|
||||
},
|
||||
]}
|
||||
>
|
||||
<TaskIcon
|
||||
sx={{
|
||||
width: "auto",
|
||||
height: "calc(18.57 / 29.5 * 100%)",
|
||||
aspectRatio: 1,
|
||||
color: buttonTextColor,
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
fontSize="calc(3cqh)"
|
||||
lineHeight="120%"
|
||||
ml="3px"
|
||||
color={buttonTextColor}
|
||||
>
|
||||
{buttonText || "Пройти тест"}
|
||||
</Typography>
|
||||
{buttonFlash && <RunningStripe />}
|
||||
</Box>
|
||||
);
|
||||
}
|
47
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/ButtonWidgetSetup/ButtonWidgetPreviewMobile.tsx
Normal file
47
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/ButtonWidgetSetup/ButtonWidgetPreviewMobile.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import TaskIcon from "@/ui_kit/TaskIcon";
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
interface Props {
|
||||
fixedSide: "left" | "right";
|
||||
buttonBackgroundColor: string;
|
||||
buttonTextColor: string;
|
||||
}
|
||||
|
||||
export default function ButtonWidgetPreviewMobile({ buttonBackgroundColor, fixedSide, buttonTextColor }: Props) {
|
||||
return (
|
||||
<Box
|
||||
sx={[
|
||||
{
|
||||
position: "absolute",
|
||||
width: "calc(22 / 520 * 100%)",
|
||||
height: "calc(22 / 262 * 100%)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: buttonBackgroundColor,
|
||||
borderRadius: "50%",
|
||||
transitionProperty: "width, height, top, left",
|
||||
transitionDuration: "0.5s",
|
||||
transitionTimingFunction: "ease",
|
||||
},
|
||||
fixedSide === "left" && {
|
||||
top: "calc(88%)",
|
||||
left: "calc(82%)",
|
||||
},
|
||||
fixedSide === "right" && {
|
||||
top: "calc(88%)",
|
||||
left: "calc(94%)",
|
||||
},
|
||||
]}
|
||||
>
|
||||
<TaskIcon
|
||||
sx={{
|
||||
width: "auto",
|
||||
height: "calc(80%)",
|
||||
aspectRatio: 1,
|
||||
color: buttonTextColor,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
@ -1,7 +1,4 @@
|
||||
import {
|
||||
ButtonWidgetFixedParams,
|
||||
ButtonWidgetParams,
|
||||
} from "@frontend/squzanswerer";
|
||||
import { ButtonWidgetFixedParams, ButtonWidgetParams } from "@frontend/squzanswerer";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@ -24,10 +21,13 @@ import RadioIcon from "@ui_kit/RadioIcon";
|
||||
import RunningStripe from "@ui_kit/RunningStripe";
|
||||
import { nanoid } from "nanoid";
|
||||
import { ReactNode, useState } from "react";
|
||||
import Dots from "../../../../assets/dots.png";
|
||||
import fixedButtonWidgetPreview from "../../../../assets/fixed-button-widget-preview.png";
|
||||
import WidgetScript from "../WidgetScript";
|
||||
import { createButtonWidgetScriptText } from "../createWidgetScriptText";
|
||||
import Dots from "../../../../../assets/dots.png";
|
||||
import fixedButtonWidgetPreview from "../../../../../assets/fixed-button-widget-preview.png";
|
||||
import WidgetScript from "../../WidgetScript";
|
||||
import { createButtonWidgetScriptText } from "../../createWidgetScriptText";
|
||||
import { useWidgetUrl } from "../../useWidgetUrl";
|
||||
import ButtonWidgetPreviewDesktop from "./ButtonWidgetPreviewDesktop";
|
||||
import ButtonWidgetPreviewMobile from "./ButtonWidgetPreviewMobile";
|
||||
|
||||
interface Props {
|
||||
step: 2 | 3;
|
||||
@ -38,25 +38,21 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
const theme = useTheme();
|
||||
const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1065));
|
||||
const quiz = useCurrentQuiz();
|
||||
const widgetUrl = useWidgetUrl();
|
||||
const [widgetWidth, setWidgetWidth] = useState<string>("");
|
||||
const [widgetHeight, setWidgetHeight] = useState<string>("");
|
||||
const [isAutoopenQuizSettingsOpen, setIsAutoopenQuizSettingsOpen] =
|
||||
useState<boolean>(false);
|
||||
const [isAutoopenQuizSettingsOpen, setIsAutoopenQuizSettingsOpen] = useState<boolean>(false);
|
||||
const [hideOnMobile, setHideOnMobile] = useState<boolean>(false);
|
||||
const [rounded, setRounded] = useState<boolean>(false);
|
||||
const [withShadow, setWithShadow] = useState<boolean>(false);
|
||||
const [buttonFlash, setButtonFlash] = useState<boolean>(false);
|
||||
const [buttonText, setButtonText] = useState<string>("");
|
||||
const [buttonBackgroundColor, setButtonBackgroundColor] = useState<string>(
|
||||
theme.palette.brightPurple.main,
|
||||
);
|
||||
const [buttonBackgroundColor, setButtonBackgroundColor] = useState<string>(theme.palette.brightPurple.main);
|
||||
const [buttonTextColor, setButtonTextColor] = useState<string>("#FFFFFF");
|
||||
const [autoShowQuiz, setAutoShowQuiz] = useState<boolean>(false);
|
||||
const [autoShowQuizTime, setAutoShowQuizTime] = useState<number>(10);
|
||||
const [openOnLeaveAttempt, setOpenOnLeaveAttempt] = useState<boolean>(false);
|
||||
const [fixedSide, setFixedSide] = useState<
|
||||
null | ButtonWidgetFixedParams["fixedSide"]
|
||||
>(null);
|
||||
const [fixedSide, setFixedSide] = useState<null | ButtonWidgetFixedParams["fixedSide"]>(null);
|
||||
const [fullScreen, setFullScreen] = useState<boolean>(false);
|
||||
|
||||
if (!quiz) return null;
|
||||
@ -96,7 +92,7 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
};
|
||||
}
|
||||
|
||||
const scriptText = createButtonWidgetScriptText(params);
|
||||
const scriptText = createButtonWidgetScriptText(params, widgetUrl);
|
||||
|
||||
return (
|
||||
<WidgetScript
|
||||
@ -186,14 +182,47 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
pt: "40px",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={fixedButtonWidgetPreview}
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
<Box
|
||||
sx={{
|
||||
position: "relative",
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<img
|
||||
src={fixedButtonWidgetPreview}
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
containerType: "size",
|
||||
}}
|
||||
>
|
||||
<ButtonWidgetPreviewDesktop
|
||||
fixedSide={fixedSide}
|
||||
buttonBackgroundColor={buttonBackgroundColor}
|
||||
buttonTextColor={buttonTextColor}
|
||||
buttonFlash={buttonFlash}
|
||||
buttonText={buttonText}
|
||||
rounded={rounded}
|
||||
withShadow={withShadow}
|
||||
/>
|
||||
{!hideOnMobile && (
|
||||
<ButtonWidgetPreviewMobile
|
||||
fixedSide={fixedSide}
|
||||
buttonBackgroundColor={buttonBackgroundColor}
|
||||
buttonTextColor={buttonTextColor}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
@ -205,7 +234,10 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
flex: "1 1 0",
|
||||
}}
|
||||
>
|
||||
<Typography fontWeight={500} color="#4D4D4D">
|
||||
<Typography
|
||||
fontWeight={500}
|
||||
color="#4D4D4D"
|
||||
>
|
||||
1. Задайте размеры окна квиза (опционально)
|
||||
</Typography>
|
||||
<CustomCheckbox
|
||||
@ -216,9 +248,7 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
<Collapse in={!fullScreen}>
|
||||
<Box sx={{ display: "flex", gap: "40px" }}>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: "20px" }}>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Ширина (px)
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Ширина (px)</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={widgetWidth}
|
||||
@ -228,9 +258,7 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: "20px" }}>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Высота (px)
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Высота (px)</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={widgetHeight}
|
||||
@ -249,7 +277,10 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
alignItems: "start",
|
||||
}}
|
||||
>
|
||||
<Typography fontWeight={500} color="#4D4D4D">
|
||||
<Typography
|
||||
fontWeight={500}
|
||||
color="#4D4D4D"
|
||||
>
|
||||
2. Конструктор кнопки
|
||||
</Typography>
|
||||
<Box
|
||||
@ -259,16 +290,12 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Цвет кнопки
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Цвет кнопки</Typography>
|
||||
<CircleColorPicker
|
||||
color={buttonBackgroundColor}
|
||||
onChange={(color) => setButtonBackgroundColor(color)}
|
||||
/>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Цвет текста кнопки
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Цвет текста кнопки</Typography>
|
||||
<CircleColorPicker
|
||||
color={buttonTextColor}
|
||||
onChange={(color) => setButtonTextColor(color)}
|
||||
@ -299,7 +326,7 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
checked={fixedSide !== null}
|
||||
handleChange={(e) => setFixedSide(e.target.checked ? "left" : null)}
|
||||
/>
|
||||
{fixedSide && (
|
||||
<Collapse in={fixedSide !== null}>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
sx={{
|
||||
@ -309,15 +336,16 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
}}
|
||||
value={fixedSide}
|
||||
onChange={(e) => {
|
||||
setFixedSide(
|
||||
e.target.value as ButtonWidgetFixedParams["fixedSide"],
|
||||
);
|
||||
setFixedSide(e.target.value as ButtonWidgetFixedParams["fixedSide"]);
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="left"
|
||||
control={
|
||||
<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />
|
||||
<Radio
|
||||
checkedIcon={<RadioCheck />}
|
||||
icon={<RadioIcon />}
|
||||
/>
|
||||
}
|
||||
label="Слева"
|
||||
sx={{
|
||||
@ -327,7 +355,10 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
<FormControlLabel
|
||||
value="right"
|
||||
control={
|
||||
<Radio checkedIcon={<RadioCheck />} icon={<RadioIcon />} />
|
||||
<Radio
|
||||
checkedIcon={<RadioCheck />}
|
||||
icon={<RadioIcon />}
|
||||
/>
|
||||
}
|
||||
label="Справа"
|
||||
sx={{
|
||||
@ -336,10 +367,8 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
)}
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Текст кнопки
|
||||
</Typography>
|
||||
</Collapse>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Текст кнопки</Typography>
|
||||
<PenaTextField
|
||||
value={buttonText}
|
||||
onChange={(e) => setButtonText(e.target.value)}
|
||||
@ -399,22 +428,16 @@ export default function ButtonWidgetSetup({ step, nextButton }: Props) {
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Показывать через
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Показывать через</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={autoShowQuizTime}
|
||||
onChange={(e) =>
|
||||
setAutoShowQuizTime(parseInt(e.target.value))
|
||||
}
|
||||
onChange={(e) => setAutoShowQuizTime(parseInt(e.target.value))}
|
||||
FormControlSx={{
|
||||
width: "90px",
|
||||
}}
|
||||
/>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
секунд
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>секунд</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Collapse>
|
@ -1,12 +1,4 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Collapse,
|
||||
Divider,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
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";
|
||||
@ -16,6 +8,7 @@ import { ReactNode, useState } from "react";
|
||||
import Dots from "../../../../assets/dots.png";
|
||||
import WidgetScript from "../WidgetScript";
|
||||
import { createContainerWidgetScriptText } from "../createWidgetScriptText";
|
||||
import { useWidgetUrl } from "../useWidgetUrl";
|
||||
|
||||
interface Props {
|
||||
step: 2 | 3;
|
||||
@ -26,8 +19,8 @@ export default function ContainerWidgetSetup({ step, nextButton }: Props) {
|
||||
const theme = useTheme();
|
||||
const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1065));
|
||||
const quiz = useCurrentQuiz();
|
||||
const [isAutoopenQuizSettingsOpen, setIsAutoopenQuizSettingsOpen] =
|
||||
useState<boolean>(false);
|
||||
const widgetUrl = useWidgetUrl();
|
||||
const [isAutoopenQuizSettingsOpen, setIsAutoopenQuizSettingsOpen] = useState<boolean>(false);
|
||||
const [widgetWidth, setWidgetWidth] = useState<string>("");
|
||||
const [widgetHeight, setWidgetHeight] = useState<string>("");
|
||||
const [hideOnMobile, setHideOnMobile] = useState<boolean>(false);
|
||||
@ -36,9 +29,7 @@ export default function ContainerWidgetSetup({ step, nextButton }: Props) {
|
||||
const [withShadow, setWithShadow] = useState<boolean>(false);
|
||||
const [buttonFlash, setButtonFlash] = useState<boolean>(false);
|
||||
const [buttonText, setButtonText] = useState<string>("");
|
||||
const [buttonBackgroundColor, setButtonBackgroundColor] = useState<string>(
|
||||
theme.palette.brightPurple.main,
|
||||
);
|
||||
const [buttonBackgroundColor, setButtonBackgroundColor] = useState<string>(theme.palette.brightPurple.main);
|
||||
const [buttonTextColor, setButtonTextColor] = useState<string>("#FFFFFF");
|
||||
const [autoShowQuiz, setAutoShowQuiz] = useState<boolean>(false);
|
||||
const [autoShowQuizTime, setAutoShowQuizTime] = useState<number>(10);
|
||||
@ -47,34 +38,32 @@ export default function ContainerWidgetSetup({ step, nextButton }: Props) {
|
||||
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 (
|
||||
<WidgetScript
|
||||
scriptText={scriptText}
|
||||
helperText="Установите код в место, в котором должен быть квиз"
|
||||
/>
|
||||
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,
|
||||
},
|
||||
widgetUrl
|
||||
);
|
||||
|
||||
return <WidgetScript scriptText={scriptText} helperText="Установите код в место, в котором должен быть квиз" />;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -139,15 +128,11 @@ export default function ContainerWidgetSetup({ step, nextButton }: Props) {
|
||||
maxWidth: "365px",
|
||||
}}
|
||||
>
|
||||
Quiz будет открыть прямо в том месте, где вы установите код на
|
||||
сайте
|
||||
Quiz будет открыть прямо в том месте, где вы установите код на сайте
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{ maxWidth: "414px", fontSize: "14px", alignSelf: "start" }}
|
||||
>
|
||||
В мобильной версии будет показана кнопка, открывающая quiz в
|
||||
модальном окне
|
||||
<Typography sx={{ maxWidth: "414px", fontSize: "14px", alignSelf: "start" }}>
|
||||
В мобильной версии будет показана кнопка, открывающая quiz в модальном окне
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
@ -164,9 +149,7 @@ export default function ContainerWidgetSetup({ step, nextButton }: Props) {
|
||||
</Typography>
|
||||
<Box sx={{ display: "flex", gap: "40px" }}>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: "20px" }}>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Ширина (px)
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Ширина (px)</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={widgetWidth}
|
||||
@ -176,9 +159,7 @@ export default function ContainerWidgetSetup({ step, nextButton }: Props) {
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: "20px" }}>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Высота (px)
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Высота (px)</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={widgetHeight}
|
||||
@ -205,36 +186,18 @@ export default function ContainerWidgetSetup({ step, nextButton }: Props) {
|
||||
gap: "40px",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Цвет кнопки
|
||||
</Typography>
|
||||
<CircleColorPicker
|
||||
color={buttonBackgroundColor}
|
||||
onChange={(color) => setButtonBackgroundColor(color)}
|
||||
/>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Цвет текста кнопки
|
||||
</Typography>
|
||||
<CircleColorPicker
|
||||
color={buttonTextColor}
|
||||
onChange={(color) => setButtonTextColor(color)}
|
||||
/>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Цвет кнопки</Typography>
|
||||
<CircleColorPicker color={buttonBackgroundColor} onChange={(color) => setButtonBackgroundColor(color)} />
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Цвет текста кнопки</Typography>
|
||||
<CircleColorPicker color={buttonTextColor} onChange={(color) => setButtonTextColor(color)} />
|
||||
</Box>
|
||||
<CustomCheckbox
|
||||
label="Отключить на мобильных устройствах"
|
||||
checked={hideOnMobile}
|
||||
handleChange={(e) => setHideOnMobile(e.target.checked)}
|
||||
/>
|
||||
<CustomCheckbox
|
||||
label="Закругленная"
|
||||
checked={rounded}
|
||||
handleChange={(e) => setRounded(e.target.checked)}
|
||||
/>
|
||||
<CustomCheckbox
|
||||
label="С тенью"
|
||||
checked={withShadow}
|
||||
handleChange={(e) => setWithShadow(e.target.checked)}
|
||||
/>
|
||||
<CustomCheckbox label="Закругленная" checked={rounded} handleChange={(e) => setRounded(e.target.checked)} />
|
||||
<CustomCheckbox label="С тенью" checked={withShadow} handleChange={(e) => setWithShadow(e.target.checked)} />
|
||||
<CustomCheckbox
|
||||
label="С бликом"
|
||||
checked={buttonFlash}
|
||||
@ -245,9 +208,7 @@ export default function ContainerWidgetSetup({ step, nextButton }: Props) {
|
||||
checked={showButtonOnMobile}
|
||||
handleChange={(e) => setShowButtonOnMobile(e.target.checked)}
|
||||
/>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Текст кнопки
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Текст кнопки</Typography>
|
||||
<PenaTextField
|
||||
value={buttonText}
|
||||
onChange={(e) => setButtonText(e.target.value)}
|
||||
@ -307,22 +268,16 @@ export default function ContainerWidgetSetup({ step, nextButton }: Props) {
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Показывать через
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Показывать через</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={autoShowQuizTime}
|
||||
onChange={(e) =>
|
||||
setAutoShowQuizTime(parseInt(e.target.value))
|
||||
}
|
||||
onChange={(e) => setAutoShowQuizTime(parseInt(e.target.value))}
|
||||
FormControlSx={{
|
||||
width: "90px",
|
||||
}}
|
||||
/>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
секунд
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>секунд</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Collapse>
|
||||
|
@ -1,10 +1,4 @@
|
||||
import {
|
||||
Box,
|
||||
Collapse,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { Box, Collapse, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||
import PenaTextField from "@ui_kit/PenaTextField";
|
||||
@ -12,6 +6,7 @@ import { ReactNode, useState } from "react";
|
||||
import Dots from "../../../../assets/dots.png";
|
||||
import WidgetScript from "../WidgetScript";
|
||||
import { createPopupWidgetScriptText } from "../createWidgetScriptText";
|
||||
import { useWidgetUrl } from "../useWidgetUrl";
|
||||
|
||||
interface Props {
|
||||
step: 2 | 3;
|
||||
@ -22,6 +17,7 @@ export default function PopupWidgetSetup({ step, nextButton }: Props) {
|
||||
const theme = useTheme();
|
||||
const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1065));
|
||||
const quiz = useCurrentQuiz();
|
||||
const widgetUrl = useWidgetUrl();
|
||||
const [widgetWidth, setWidgetWidth] = useState<string>("");
|
||||
const [widgetHeight, setWidgetHeight] = useState<string>("");
|
||||
const [hideOnMobile, setHideOnMobile] = useState<boolean>(false);
|
||||
@ -32,27 +28,25 @@ export default function PopupWidgetSetup({ step, nextButton }: Props) {
|
||||
if (!quiz) return null;
|
||||
|
||||
if (step === 3) {
|
||||
const scriptText = createPopupWidgetScriptText({
|
||||
quizId: quiz.qid,
|
||||
hideOnMobile: hideOnMobile || undefined,
|
||||
autoShowQuizTime: autoShowQuizTime,
|
||||
openOnLeaveAttempt: openOnLeaveAttempt || undefined,
|
||||
fullScreen: fullScreen || undefined,
|
||||
dialogDimensions:
|
||||
!fullScreen && (widgetWidth || widgetHeight)
|
||||
? {
|
||||
width: widgetWidth ? `${widgetWidth}px` : "100%",
|
||||
height: widgetHeight ? `${widgetHeight}px` : "100%",
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
|
||||
return (
|
||||
<WidgetScript
|
||||
scriptText={scriptText}
|
||||
helperText="Установите код внутрь тэга head"
|
||||
/>
|
||||
const scriptText = createPopupWidgetScriptText(
|
||||
{
|
||||
quizId: quiz.qid,
|
||||
hideOnMobile: hideOnMobile || undefined,
|
||||
autoShowQuizTime: autoShowQuizTime,
|
||||
openOnLeaveAttempt: openOnLeaveAttempt || undefined,
|
||||
fullScreen: fullScreen || undefined,
|
||||
dialogDimensions:
|
||||
!fullScreen && (widgetWidth || widgetHeight)
|
||||
? {
|
||||
width: widgetWidth ? `${widgetWidth}px` : "100%",
|
||||
height: widgetHeight ? `${widgetHeight}px` : "100%",
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
widgetUrl
|
||||
);
|
||||
|
||||
return <WidgetScript scriptText={scriptText} helperText="Установите код внутрь тэга head" />;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -147,9 +141,7 @@ export default function PopupWidgetSetup({ step, nextButton }: Props) {
|
||||
gap: "20px",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Ширина окна (px)
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Ширина окна (px)</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={widgetWidth}
|
||||
@ -165,9 +157,7 @@ export default function PopupWidgetSetup({ step, nextButton }: Props) {
|
||||
gap: "20px",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Высота окна (px)
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Высота окна (px)</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={widgetHeight}
|
||||
@ -185,9 +175,7 @@ export default function PopupWidgetSetup({ step, nextButton }: Props) {
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Показывать через
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Показывать через</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={autoShowQuizTime}
|
||||
@ -196,9 +184,7 @@ export default function PopupWidgetSetup({ step, nextButton }: Props) {
|
||||
width: "90px",
|
||||
}}
|
||||
/>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
секунд
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>секунд</Typography>
|
||||
</Box>
|
||||
<CustomCheckbox
|
||||
label="Открывать квиз при попытке уйти с сайта"
|
||||
|
125
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/SideWidgetSetup/SideWidgetSetup.tsx
125
src/pages/InstallQuiz/QuizInstallationCard/WidgetSetupByType/SideWidgetSetup/SideWidgetSetup.tsx
@ -1,11 +1,5 @@
|
||||
import { SideWidgetParams } from "@frontend/squzanswerer";
|
||||
import {
|
||||
Box,
|
||||
Collapse,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { Box, Collapse, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import CircleColorPicker from "@ui_kit/CircleColorPicker";
|
||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||
@ -15,6 +9,7 @@ import sideWidgetPreviewLeft from "../../../../../assets/side-widget-preview-lef
|
||||
import sideWidgetPreviewRight from "../../../../../assets/side-widget-preview-right.png";
|
||||
import WidgetScript from "../../WidgetScript";
|
||||
import { createSideWidgetScriptText } from "../../createWidgetScriptText";
|
||||
import { useWidgetUrl } from "../../useWidgetUrl";
|
||||
import SideWidgetPositionButton from "./SideWidgetPositionButton";
|
||||
|
||||
interface Props {
|
||||
@ -26,49 +21,45 @@ export default function SideWidgetSetup({ step, nextButton }: Props) {
|
||||
const theme = useTheme();
|
||||
const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1065));
|
||||
const quiz = useCurrentQuiz();
|
||||
const widgetUrl = useWidgetUrl();
|
||||
const [widgetWidth, setWidgetWidth] = useState<string>("");
|
||||
const [widgetHeight, setWidgetHeight] = useState<string>("");
|
||||
const [hideOnMobile, setHideOnMobile] = useState<boolean>(false);
|
||||
const [autoShowQuiz, setAutoShowQuiz] = useState<boolean>(false);
|
||||
const [autoShowQuizTime, setAutoShowQuizTime] = useState<number>(10);
|
||||
const [autoShowWidgetTime, setAutoShowWidgetTime] = useState<number>(10);
|
||||
const [position, setPosition] =
|
||||
useState<SideWidgetParams["position"]>("left");
|
||||
const [position, setPosition] = useState<SideWidgetParams["position"]>("left");
|
||||
const [fullScreen, setFullScreen] = useState<boolean>(false);
|
||||
const [buttonFlash, setButtonFlash] = useState<boolean>(false);
|
||||
const [buttonBackgroundColor, setButtonBackgroundColor] = useState<string>(
|
||||
theme.palette.brightPurple.main,
|
||||
);
|
||||
const [buttonBackgroundColor, setButtonBackgroundColor] = useState<string>(theme.palette.brightPurple.main);
|
||||
const [buttonTextColor, setButtonTextColor] = useState<string>("#FFFFFF");
|
||||
|
||||
if (!quiz) return null;
|
||||
|
||||
if (step === 3) {
|
||||
const scriptText = createSideWidgetScriptText({
|
||||
quizId: quiz.qid,
|
||||
position: position,
|
||||
hideOnMobile: hideOnMobile || undefined,
|
||||
autoShowQuizTime: autoShowQuiz ? autoShowQuizTime : undefined,
|
||||
autoShowWidgetTime: autoShowWidgetTime || undefined,
|
||||
fullScreen: fullScreen || undefined,
|
||||
buttonFlash: buttonFlash || undefined,
|
||||
buttonTextColor,
|
||||
buttonBackgroundColor,
|
||||
dialogDimensions:
|
||||
!fullScreen && (widgetWidth || widgetHeight)
|
||||
? {
|
||||
width: widgetWidth ? `${widgetWidth}px` : "100%",
|
||||
height: widgetHeight ? `${widgetHeight}px` : "100%",
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
|
||||
return (
|
||||
<WidgetScript
|
||||
scriptText={scriptText}
|
||||
helperText="Установите код внутрь тэга head"
|
||||
/>
|
||||
const scriptText = createSideWidgetScriptText(
|
||||
{
|
||||
quizId: quiz.qid,
|
||||
position: position,
|
||||
hideOnMobile: hideOnMobile || undefined,
|
||||
autoShowQuizTime: autoShowQuiz ? autoShowQuizTime : undefined,
|
||||
autoShowWidgetTime: autoShowWidgetTime || undefined,
|
||||
fullScreen: fullScreen || undefined,
|
||||
buttonFlash: buttonFlash || undefined,
|
||||
buttonTextColor,
|
||||
buttonBackgroundColor,
|
||||
dialogDimensions:
|
||||
!fullScreen && (widgetWidth || widgetHeight)
|
||||
? {
|
||||
width: widgetWidth ? `${widgetWidth}px` : "100%",
|
||||
height: widgetHeight ? `${widgetHeight}px` : "100%",
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
widgetUrl
|
||||
);
|
||||
|
||||
return <WidgetScript scriptText={scriptText} helperText="Установите код внутрь тэга head" />;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -92,11 +83,7 @@ export default function SideWidgetSetup({ step, nextButton }: Props) {
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={
|
||||
position === "left"
|
||||
? sideWidgetPreviewLeft
|
||||
: sideWidgetPreviewRight
|
||||
}
|
||||
src={position === "left" ? sideWidgetPreviewLeft : sideWidgetPreviewRight}
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
@ -133,9 +120,7 @@ export default function SideWidgetSetup({ step, nextButton }: Props) {
|
||||
position="left"
|
||||
onClick={() => setPosition("left")}
|
||||
/>
|
||||
<Typography color={theme.palette.grey2.main}>
|
||||
Слева снизу
|
||||
</Typography>
|
||||
<Typography color={theme.palette.grey2.main}>Слева снизу</Typography>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
@ -150,9 +135,7 @@ export default function SideWidgetSetup({ step, nextButton }: Props) {
|
||||
position="right"
|
||||
onClick={() => setPosition("right")}
|
||||
/>
|
||||
<Typography color={theme.palette.grey2.main}>
|
||||
Справа снизу
|
||||
</Typography>
|
||||
<Typography color={theme.palette.grey2.main}>Справа снизу</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<CustomCheckbox
|
||||
@ -174,9 +157,7 @@ export default function SideWidgetSetup({ step, nextButton }: Props) {
|
||||
gap: "20px",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Ширина окна (px)
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Ширина окна (px)</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={widgetWidth}
|
||||
@ -192,9 +173,7 @@ export default function SideWidgetSetup({ step, nextButton }: Props) {
|
||||
gap: "20px",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Высота окна (px)
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Высота окна (px)</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={widgetHeight}
|
||||
@ -212,20 +191,10 @@ export default function SideWidgetSetup({ step, nextButton }: Props) {
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Цвет кнопки
|
||||
</Typography>
|
||||
<CircleColorPicker
|
||||
color={buttonBackgroundColor}
|
||||
onChange={(color) => setButtonBackgroundColor(color)}
|
||||
/>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Цвет текста кнопки
|
||||
</Typography>
|
||||
<CircleColorPicker
|
||||
color={buttonTextColor}
|
||||
onChange={(color) => setButtonTextColor(color)}
|
||||
/>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Цвет кнопки</Typography>
|
||||
<CircleColorPicker color={buttonBackgroundColor} onChange={(color) => setButtonBackgroundColor(color)} />
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Цвет текста кнопки</Typography>
|
||||
<CircleColorPicker color={buttonTextColor} onChange={(color) => setButtonTextColor(color)} />
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
@ -234,9 +203,7 @@ export default function SideWidgetSetup({ step, nextButton }: Props) {
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Показывать кнопку через
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Показывать кнопку через</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={autoShowWidgetTime}
|
||||
@ -245,15 +212,9 @@ export default function SideWidgetSetup({ step, nextButton }: Props) {
|
||||
width: "90px",
|
||||
}}
|
||||
/>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
секунд
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>секунд</Typography>
|
||||
</Box>
|
||||
<CustomCheckbox
|
||||
label="С бликом"
|
||||
checked={buttonFlash}
|
||||
handleChange={(e) => setButtonFlash(e.target.checked)}
|
||||
/>
|
||||
<CustomCheckbox label="С бликом" checked={buttonFlash} handleChange={(e) => setButtonFlash(e.target.checked)} />
|
||||
<Box>
|
||||
<CustomCheckbox
|
||||
label="Автооткрытие виджета при входе на сайт"
|
||||
@ -269,9 +230,7 @@ export default function SideWidgetSetup({ step, nextButton }: Props) {
|
||||
mt: "14px",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
Показывать через
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>Показывать через</Typography>
|
||||
<PenaTextField
|
||||
type="number"
|
||||
value={autoShowQuizTime}
|
||||
@ -280,9 +239,7 @@ export default function SideWidgetSetup({ step, nextButton }: Props) {
|
||||
width: "90px",
|
||||
}}
|
||||
/>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>
|
||||
секунд
|
||||
</Typography>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>секунд</Typography>
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{
|
||||
|
@ -5,50 +5,46 @@ import {
|
||||
ContainerWidgetParams,
|
||||
PopupWidgetParams,
|
||||
SideWidgetParams,
|
||||
WidgetType,
|
||||
} from "@frontend/squzanswerer";
|
||||
|
||||
export function createContainerWidgetScriptText(params: ContainerWidgetParams) {
|
||||
export function createContainerWidgetScriptText(params: ContainerWidgetParams, widgetUrl: string) {
|
||||
return `<div id="${params.selector.slice(1)}"></div>
|
||||
<script type="module">
|
||||
import { ContainerWidget } from "https://hbpn.link/export/pub.js";
|
||||
import { ContainerWidget } from "${widgetUrl}";
|
||||
|
||||
new ContainerWidget(${JSON.stringify(params, null, 4)});
|
||||
</script>`;
|
||||
}
|
||||
|
||||
export function createButtonWidgetScriptText(
|
||||
params: ButtonWidgetParams | ButtonWidgetFixedParams,
|
||||
) {
|
||||
const widgetClassName =
|
||||
"fixedSide" in params ? "ButtonWidgetFixed" : "ButtonWidget";
|
||||
export function createButtonWidgetScriptText(params: ButtonWidgetParams | ButtonWidgetFixedParams, widgetUrl: string) {
|
||||
const widgetClassName = "fixedSide" in params ? "ButtonWidgetFixed" : "ButtonWidget";
|
||||
|
||||
return `${"selector" in params ? `<div id="${params.selector.slice(1)}"></div>\n` : ""}<script type="module">
|
||||
import { ${widgetClassName} } from "https://hbpn.link/export/pub.js";
|
||||
import { ${widgetClassName} } from "${widgetUrl}";
|
||||
|
||||
new ${widgetClassName}(${JSON.stringify(params, null, 4)});
|
||||
</script>`;
|
||||
}
|
||||
|
||||
export function createPopupWidgetScriptText(params: PopupWidgetParams) {
|
||||
export function createPopupWidgetScriptText(params: PopupWidgetParams, widgetUrl: string) {
|
||||
return `<script type="module">
|
||||
import { PopupWidget } from "https://hbpn.link/export/pub.js";
|
||||
import { PopupWidget } from "${widgetUrl}";
|
||||
|
||||
new PopupWidget(${JSON.stringify(params, null, 4)});
|
||||
</script>`;
|
||||
}
|
||||
|
||||
export function createSideWidgetScriptText(params: SideWidgetParams) {
|
||||
export function createSideWidgetScriptText(params: SideWidgetParams, widgetUrl: string) {
|
||||
return `<script type="module">
|
||||
import { SideWidget } from "https://hbpn.link/export/pub.js";
|
||||
import { SideWidget } from "${widgetUrl}";
|
||||
|
||||
new SideWidget(${JSON.stringify(params, null, 4)});
|
||||
</script>`;
|
||||
}
|
||||
|
||||
export function createBannerWidgetScriptText(params: BannerWidgetParams) {
|
||||
export function createBannerWidgetScriptText(params: BannerWidgetParams, widgetUrl: string) {
|
||||
return `<script type="module">
|
||||
import { BannerWidget } from "https://hbpn.link/export/pub.js";
|
||||
import { BannerWidget } from "${widgetUrl}";
|
||||
|
||||
new BannerWidget(${JSON.stringify(params, null, 4)});
|
||||
</script>`;
|
||||
|
@ -0,0 +1,7 @@
|
||||
import { useDomainDefine } from "@/utils/hooks/useDomainDefine";
|
||||
|
||||
export function useWidgetUrl() {
|
||||
const { isTestServer } = useDomainDefine();
|
||||
|
||||
return `https://${isTestServer ? "s." : ""}hbpn.link/export/pub.js`;
|
||||
}
|
@ -24,6 +24,10 @@ import { redirect } from "react-router-dom";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
|
||||
export type TitleKeys = "contacts" | "company" | "deal" | "buyers";
|
||||
export type TagQuestionObject = {
|
||||
backendId: string;
|
||||
title: string;
|
||||
};
|
||||
|
||||
export type TQuestionEntity = Record<TitleKeys, string[] | []>;
|
||||
type IntegrationsModalProps = {
|
||||
@ -86,7 +90,7 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
|
||||
const [account, error] = await getAccount();
|
||||
|
||||
if (error) {
|
||||
enqueueSnackbar(error)
|
||||
if (!error.includes("Not Found")) enqueueSnackbar(error)
|
||||
setAccountInfo(null);
|
||||
}
|
||||
if (account) {
|
||||
@ -97,7 +101,7 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
|
||||
const [settingsResponse, error] = await getIntegrationRules(quizID.toString());
|
||||
|
||||
if (error) {
|
||||
enqueueSnackbar(error)
|
||||
if (!error.includes("Not Found")) enqueueSnackbar(error)
|
||||
setIntegrationRules(null);
|
||||
}
|
||||
if (settingsResponse) {
|
||||
@ -182,10 +186,10 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
|
||||
isSettingsAvailable: true,
|
||||
component: (
|
||||
<AmoStep6
|
||||
tags={tags}
|
||||
tagsNames={tags}
|
||||
handlePrevStep={handlePrevStep}
|
||||
handleNextStep={handleNextStep}
|
||||
setTags={setTags}
|
||||
setTagsNames={setTags}
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
FC,
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
@ -12,33 +13,34 @@ import { TagKeys, TTags } from "../AmoCRMModal";
|
||||
import Box from "@mui/material/Box";
|
||||
import { ItemsSelectionView } from "../IntegrationStep7/ItemsSelectionView/ItemsSelectionView";
|
||||
import { TagsDetailsView } from "./TagsDetailsView/TagsDetailsView";
|
||||
import { Tag } from "@api/integration";
|
||||
|
||||
type Props = {
|
||||
handleNextStep: () => void;
|
||||
handlePrevStep: () => void;
|
||||
tags: TTags;
|
||||
setTags: Dispatch<SetStateAction<TTags>>;
|
||||
tagsNames: TTags;
|
||||
setTagsNames: Dispatch<SetStateAction<TTags>>;
|
||||
};
|
||||
|
||||
export const AmoStep6: FC<Props> = ({
|
||||
handleNextStep,
|
||||
handlePrevStep,
|
||||
tags,
|
||||
setTags,
|
||||
tagsNames,
|
||||
setTagsNames
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const [isSelection, setIsSelection] = useState<boolean>(false);
|
||||
const [activeItem, setActiveItem] = useState<string | null>(null);
|
||||
const [selectedValue, setSelectedValue] = useState<string | null>(null);
|
||||
|
||||
const [tags, setTags] = useState<Tag[]>([]);
|
||||
const handleAdd = useCallback(() => {
|
||||
if (!activeItem || !selectedValue) return;
|
||||
|
||||
setTags((prevState) => ({
|
||||
setTagsNames((prevState) => ({
|
||||
...prevState,
|
||||
[activeItem]: [...prevState[activeItem as TagKeys], selectedValue],
|
||||
}));
|
||||
}, [activeItem, setTags, selectedValue]);
|
||||
}, [activeItem, setTagsNames, selectedValue]);
|
||||
|
||||
const items = useMemo(
|
||||
() => ["#тег с результатом 1", "#еще один тег с результатом 2", "#тег"],
|
||||
@ -56,7 +58,8 @@ export const AmoStep6: FC<Props> = ({
|
||||
>
|
||||
{isSelection ? (
|
||||
<ItemsSelectionView
|
||||
items={items}
|
||||
parentTags={tags}
|
||||
setTags={setTags}
|
||||
selectedValue={selectedValue}
|
||||
setSelectedValue={setSelectedValue}
|
||||
type={"typeTags"}
|
||||
@ -75,7 +78,7 @@ export const AmoStep6: FC<Props> = ({
|
||||
setIsSelection={setIsSelection}
|
||||
handlePrevStep={handlePrevStep}
|
||||
handleNextStep={handleNextStep}
|
||||
tags={tags}
|
||||
tagsNames={tagsNames}
|
||||
setActiveItem={setActiveItem}
|
||||
/>
|
||||
)}
|
||||
|
10
src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/TagsDetailsView/TagsDetailsView.tsx
10
src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/TagsDetailsView/TagsDetailsView.tsx
@ -8,14 +8,14 @@ type TagsDetailsViewProps = {
|
||||
setIsSelection: (value: boolean) => void;
|
||||
handlePrevStep: () => void;
|
||||
handleNextStep: () => void;
|
||||
tags: TTags;
|
||||
tagsNames: TTags;
|
||||
setActiveItem: (value: string | null) => void;
|
||||
};
|
||||
|
||||
export const TagsDetailsView: FC<TagsDetailsViewProps> = ({
|
||||
handlePrevStep,
|
||||
handleNextStep,
|
||||
tags,
|
||||
tagsNames,
|
||||
setActiveItem,
|
||||
setIsSelection,
|
||||
}) => {
|
||||
@ -68,8 +68,8 @@ export const TagsDetailsView: FC<TagsDetailsViewProps> = ({
|
||||
justifyContent: "start",
|
||||
}}
|
||||
>
|
||||
{tags &&
|
||||
Object.keys(tags).map((item) => (
|
||||
{tagsNames &&
|
||||
Object.keys(tagsNames).map((item) => (
|
||||
<Item
|
||||
key={item}
|
||||
title={item as TagKeys}
|
||||
@ -77,7 +77,7 @@ export const TagsDetailsView: FC<TagsDetailsViewProps> = ({
|
||||
setIsSelection(true);
|
||||
setActiveItem(item);
|
||||
}}
|
||||
data={tags}
|
||||
data={tagsNames}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
|
@ -9,9 +9,11 @@ import {
|
||||
} from "react";
|
||||
import { ItemsSelectionView } from "./ItemsSelectionView/ItemsSelectionView";
|
||||
import { ItemDetailsView } from "./ItemDetailsView/ItemDetailsView";
|
||||
import { TitleKeys, TQuestionEntity } from "../AmoCRMModal";
|
||||
import { TagQuestionObject, TitleKeys, TQuestionEntity } from "../AmoCRMModal";
|
||||
import Box from "@mui/material/Box";
|
||||
import type { AllTypesQuestion } from "@model/questionTypes/shared"
|
||||
import { getQuestionById } from "@/stores/questions/actions";
|
||||
import { useQuestionsStore } from "@/stores/questions/store";
|
||||
|
||||
type Props = {
|
||||
handlePrevStep: () => void;
|
||||
@ -42,10 +44,33 @@ export const AmoStep7: FC<Props> = ({
|
||||
}));
|
||||
}, [activeItem, setQuestionEntity, selectedValue]);
|
||||
|
||||
const items = useMemo(
|
||||
() => ["Город", "Имя", "Фамилия", "Отчество", "Контрагент"],
|
||||
const items: TagQuestionObject[] = useMemo(
|
||||
() => Object.values(questions)
|
||||
.filter(({ type }) =>
|
||||
type !== "result"
|
||||
&& type !== null)
|
||||
.map(({ backendId, title }) => ({
|
||||
backendId: backendId.toString(),
|
||||
title
|
||||
})),
|
||||
[],
|
||||
);
|
||||
const translatedQuestionEntity = useMemo(() => {
|
||||
const translated = {} as TQuestionEntity;
|
||||
|
||||
for (let key in questionEntity) {
|
||||
// /* ... делать что-то с obj[key] ... */
|
||||
translated[key] = questionEntity[key].map((id) =>
|
||||
questions.find((q) => q.backendId === Number(id))?.title || id
|
||||
)
|
||||
}
|
||||
|
||||
console.log("questionEntity", questionEntity)
|
||||
console.log("translated", translated)
|
||||
return translated
|
||||
},
|
||||
[questionEntity],
|
||||
)
|
||||
|
||||
return (
|
||||
<Box
|
||||
@ -59,6 +84,7 @@ export const AmoStep7: FC<Props> = ({
|
||||
{isSelection ? (
|
||||
<ItemsSelectionView
|
||||
items={items}
|
||||
type="typeQuestions"
|
||||
selectedValue={selectedValue}
|
||||
setSelectedValue={setSelectedValue}
|
||||
onSmallBtnClick={() => {
|
||||
@ -70,14 +96,13 @@ export const AmoStep7: FC<Props> = ({
|
||||
setActiveItem(null);
|
||||
setIsSelection(false);
|
||||
}}
|
||||
questions={questions}
|
||||
/>
|
||||
) : (
|
||||
<ItemDetailsView
|
||||
setIsSelection={setIsSelection}
|
||||
handleLargeBtn={handleNextStep}
|
||||
handleSmallBtn={handlePrevStep}
|
||||
questionEntity={questionEntity}
|
||||
questionEntity={translatedQuestionEntity}
|
||||
setActiveItem={setActiveItem}
|
||||
/>
|
||||
)}
|
||||
|
@ -12,6 +12,8 @@ type ItemProps = {
|
||||
export const Item: FC<ItemProps> = ({ title, onAddBtnClick, data }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
console.log("title")
|
||||
console.log(data)
|
||||
const titleDictionary = {
|
||||
contact: "Контакт",
|
||||
company: "Компания",
|
||||
|
@ -3,14 +3,18 @@ import { CustomRadioGroup } from "../../../../../components/CustomRadioGroup/Cus
|
||||
import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock";
|
||||
import { FC } from "react";
|
||||
import { AllTypesQuestion } from "@/model/questionTypes/shared";
|
||||
import type { TagQuestionObject } from "@/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal"
|
||||
import { Tag } from "@api/integration";
|
||||
|
||||
type ItemsSelectionViewProps = {
|
||||
type?: string;
|
||||
items: string[];
|
||||
items?: TagQuestionObject[];
|
||||
selectedValue: string | null;
|
||||
setSelectedValue: (value: string | null) => void;
|
||||
onLargeBtnClick: () => void;
|
||||
onSmallBtnClick: () => void;
|
||||
setTags: (setValueFunc: (value: Tag[]) => Tag[]) => void;
|
||||
parentTags: Tag[]
|
||||
};
|
||||
|
||||
export const ItemsSelectionView: FC<ItemsSelectionViewProps> = ({
|
||||
@ -20,7 +24,11 @@ export const ItemsSelectionView: FC<ItemsSelectionViewProps> = ({
|
||||
onLargeBtnClick,
|
||||
onSmallBtnClick,
|
||||
type,
|
||||
parentTags,
|
||||
setTags
|
||||
}) => {
|
||||
console.log("items тегов")
|
||||
console.log(items)
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
@ -42,6 +50,8 @@ export const ItemsSelectionView: FC<ItemsSelectionViewProps> = ({
|
||||
<CustomRadioGroup
|
||||
type={type}
|
||||
items={items}
|
||||
tags={parentTags}
|
||||
setTags={setTags}
|
||||
selectedValue={selectedValue}
|
||||
setSelectedValue={setSelectedValue}
|
||||
/>
|
||||
|
@ -1,23 +1,18 @@
|
||||
import React, { useEffect } from "react";
|
||||
import React from "react";
|
||||
import { CssBaseline, useMediaQuery, useTheme } from "@mui/material";
|
||||
import Header from "./HeaderLanding";
|
||||
import Footer from "./FooterLanding";
|
||||
import Hero from "./Hero";
|
||||
import Questions from "./Questions";
|
||||
import Counter from "./Counter";
|
||||
import Blog from "./Blog";
|
||||
import HowItWorks from "./HowItWorks";
|
||||
import BusinessPluses from "./BusinessPluses";
|
||||
import HowToUse from "./HowToUse";
|
||||
|
||||
import StartWithTemplates from "./StartWithTemplates";
|
||||
import WhatTheFeatures from "./WhatTheFeatures";
|
||||
import FullScreenDialog from "./headerMobileLanding";
|
||||
import Collaboration from "./Collaboration";
|
||||
import { clearAuthToken, setAuthToken } from "@frontend/kitui";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { clearUserData, setUserId, useUserStore } from "@root/user";
|
||||
import { cleanAuthTicketData } from "@root/ticket";
|
||||
import { Tariffs } from "@/pages/Landing/Tariffs/Tariffs";
|
||||
|
||||
export default function Landing() {
|
||||
const theme = useTheme();
|
||||
@ -47,6 +42,7 @@ export default function Landing() {
|
||||
<Header />
|
||||
<Hero />
|
||||
<Counter />
|
||||
<Tariffs />
|
||||
{/* <Collaboration/> */}
|
||||
<HowItWorks />
|
||||
<BusinessPluses />
|
||||
|
111
src/pages/Landing/Tariffs/TariffCard/TariffCard.tsx
Normal file
111
src/pages/Landing/Tariffs/TariffCard/TariffCard.tsx
Normal file
@ -0,0 +1,111 @@
|
||||
import { Box, Button, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { FC } from "react";
|
||||
import { DurationTariffIcon } from "@/pages/Landing/Tariffs/TariffCard/icons/DurationTariffIcon";
|
||||
import { TrialTariffIcon } from "@/pages/Landing/Tariffs/TariffCard/icons/TrialTariffIcon";
|
||||
import { RequestsTariffIcon } from "@/pages/Landing/Tariffs/TariffCard/icons/RequestsTariffIcon";
|
||||
import { Link, useLocation } from "react-router-dom";
|
||||
|
||||
type TariffCardProps = {
|
||||
type: "requests" | "duration" | "trial";
|
||||
name: string;
|
||||
description: string;
|
||||
actualPrice: string;
|
||||
oldPrice?: string;
|
||||
discount?: string;
|
||||
};
|
||||
|
||||
const icons = {
|
||||
requests: <RequestsTariffIcon />,
|
||||
duration: <DurationTariffIcon />,
|
||||
trial: <TrialTariffIcon />,
|
||||
};
|
||||
|
||||
export const TariffCard: FC<TariffCardProps> = ({ type, name, actualPrice, oldPrice, discount, description }) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1140));
|
||||
|
||||
const location = useLocation();
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: isMobile ? "321px" : "360px",
|
||||
height: "313px",
|
||||
background: type === "trial" ? "#7E2AEA" : "#333646",
|
||||
borderRadius: "12px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", padding: "20px", justifyContent: "space-between", alignItems: "center" }}>
|
||||
<Box sx={{ display: "flex", gap: "15px" }}>
|
||||
{icons[type]}
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
background: "#7E2AEA",
|
||||
padding: "8px 10px",
|
||||
borderRadius: "8px",
|
||||
height: "fit-content",
|
||||
}}
|
||||
>
|
||||
{discount && <Typography sx={{ color: "#FFF", lineHeight: "1" }}>-{discount}%</Typography>}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", gap: "15px" }}>
|
||||
{oldPrice && (
|
||||
<Typography
|
||||
sx={{
|
||||
color: "#9A9AAF",
|
||||
fontSize: "16px",
|
||||
textDecoration: "line-through",
|
||||
textDecorationColor: "#FB5607",
|
||||
textDecorationThickness: "1px",
|
||||
}}
|
||||
>
|
||||
{oldPrice} ₽
|
||||
</Typography>
|
||||
)}
|
||||
{actualPrice && (
|
||||
<Typography
|
||||
sx={{
|
||||
color: "#FFF",
|
||||
fontSize: "20px",
|
||||
}}
|
||||
>
|
||||
{actualPrice} ₽
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box sx={{ marginTop: "5px", padding: "0 20px", display: "flex", flexDirection: "column", gap: "10px" }}>
|
||||
{name && <Typography sx={{ color: "#FFF", fontSize: "24px" }}>{name}</Typography>}
|
||||
{description && <Typography sx={{ color: type === "trial" ? "#EEEFF4" : "#9A9AAF" }}>{description}</Typography>}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "auto",
|
||||
height: "64px",
|
||||
background: type === "trial" ? "#5A1EA8" : "rgba(154, 154, 175, 0.5)",
|
||||
borderRadius: "0 0 12px 12px",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
component={Link}
|
||||
to={"/signin"}
|
||||
state={{ backgroundLocation: location }}
|
||||
sx={{
|
||||
color: "#FFF",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
Выбрать
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
@ -0,0 +1,18 @@
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
export const DurationTariffIcon = () => {
|
||||
return (
|
||||
<Box>
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="36" height="36" rx="6" fill="#2B2C39" />
|
||||
<circle cx="18" cy="18" r="10" stroke="#944FEE" strokeWidth="1.5" />
|
||||
<path
|
||||
d="M18 14V17.7324C18 17.8996 18.0836 18.0557 18.2226 18.1484L21 20"
|
||||
stroke="#944FEE"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>
|
||||
</Box>
|
||||
);
|
||||
};
|
@ -0,0 +1,48 @@
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
export const RequestsTariffIcon = () => {
|
||||
return (
|
||||
<Box>
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="36" height="36" rx="6" fill="#2B2C39" />
|
||||
<circle
|
||||
cx="3.40426"
|
||||
cy="3.40426"
|
||||
r="3.40426"
|
||||
transform="matrix(-1 0 0 1 21.625 10.5)"
|
||||
stroke="#944FEE"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
<path
|
||||
d="M12.2578 22.3565C12.2578 21.6242 12.7181 20.9711 13.4077 20.7248V20.7248C16.5166 19.6145 19.9139 19.6145 23.0228 20.7248V20.7248C23.7124 20.9711 24.1727 21.6242 24.1727 22.3565V23.4761C24.1727 24.4866 23.2776 25.2629 22.2772 25.12L21.9437 25.0724C19.4706 24.7191 16.9599 24.7191 14.4869 25.0724L14.1533 25.12C13.1529 25.2629 12.2578 24.4866 12.2578 23.4761V22.3565Z"
|
||||
stroke="#944FEE"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
<path
|
||||
d="M23.3174 17.4042C24.7947 17.4042 25.9922 16.2067 25.9922 14.7295C25.9922 13.2522 24.7947 12.0547 23.3174 12.0547"
|
||||
stroke="#944FEE"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M26.2471 23.5075L26.5092 23.5449C27.2952 23.6572 27.9985 23.0473 27.9985 22.2533V21.3736C27.9985 20.7983 27.6368 20.2851 27.095 20.0916C26.5546 19.8985 26.003 19.7482 25.4453 19.6406"
|
||||
stroke="#944FEE"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M12.6826 17.4042C11.2053 17.4042 10.0078 16.2067 10.0078 14.7295C10.0078 13.2522 11.2053 12.0547 12.6826 12.0547"
|
||||
stroke="#944FEE"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M9.75289 23.5075L9.49082 23.5449C8.70476 23.6572 8.0015 23.0473 8.0015 22.2533V21.3736C8.0015 20.7983 8.36316 20.2851 8.90496 20.0916C9.44541 19.8985 9.99696 19.7482 10.5547 19.6406"
|
||||
stroke="#944FEE"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>
|
||||
</Box>
|
||||
);
|
||||
};
|
@ -0,0 +1,27 @@
|
||||
import { Box } from "@mui/material";
|
||||
|
||||
export const TrialTariffIcon = () => {
|
||||
return (
|
||||
<Box>
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="36" height="36" rx="6" fill="white" />
|
||||
<path d="M18 12.1694V13.8361" stroke="#7E2AEA" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path d="M18 22.1694V23.8361" stroke="#7E2AEA" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path
|
||||
d="M18 28C23.5228 28 28 23.5228 28 18C28 12.4772 23.5228 8 18 8C12.4772 8 8 12.4772 8 18C8 23.5228 12.4772 28 18 28Z"
|
||||
stroke="#7E2AEA"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M15.4974 22.1639H19.2474C19.7999 22.1639 20.3298 21.9444 20.7205 21.5537C21.1112 21.163 21.3307 20.6331 21.3307 20.0806C21.3307 19.528 21.1112 18.9981 20.7205 18.6074C20.3298 18.2167 19.7999 17.9972 19.2474 17.9972H16.7474C16.1949 17.9972 15.665 17.7777 15.2743 17.387C14.8836 16.9963 14.6641 16.4664 14.6641 15.9139C14.6641 15.3614 14.8836 14.8315 15.2743 14.4408C15.665 14.0501 16.1949 13.8306 16.7474 13.8306H20.4974"
|
||||
stroke="#7E2AEA"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</Box>
|
||||
);
|
||||
};
|
173
src/pages/Landing/Tariffs/Tariffs.tsx
Normal file
173
src/pages/Landing/Tariffs/Tariffs.tsx
Normal file
@ -0,0 +1,173 @@
|
||||
import Box from "@mui/material/Box";
|
||||
import { CssBaseline, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { Swiper, SwiperSlide } from "swiper/react";
|
||||
import { Navigation, Pagination } from "swiper/modules";
|
||||
import SectionStyled from "@/pages/Landing/SectionStyled";
|
||||
import React, { useMemo } from "react";
|
||||
import { TariffCard } from "@/pages/Landing/Tariffs/TariffCard/TariffCard";
|
||||
import "swiper/css";
|
||||
import "swiper/css/pagination";
|
||||
import "swiper/css/navigation";
|
||||
|
||||
export type Tariff = {
|
||||
name: string;
|
||||
type: "requests" | "duration" | "trial";
|
||||
description: string;
|
||||
actualPrice: string;
|
||||
oldPrice?: string;
|
||||
discount?: string;
|
||||
};
|
||||
|
||||
const swiperStyles = `
|
||||
.mySwiper .swiper-pagination-bullet {
|
||||
background: #9A9AAF;
|
||||
margin-top: 40px;
|
||||
}
|
||||
.mySwiper .swiper-pagination {
|
||||
position: relative;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.mySwiper .swiper-button-next, .mySwiper .swiper-button-prev {
|
||||
width: 37.5px;
|
||||
height: 37.5px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
margin-top: -40px;
|
||||
}
|
||||
.mySwiper .swiper-button-next:after, .mySwiper .swiper-button-prev:after {
|
||||
color: black;
|
||||
font-size: 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const Tariffs = () => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||
|
||||
const tariffs: Tariff[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
name: "Бесплатно 14 дней",
|
||||
type: "trial",
|
||||
description:
|
||||
"Каждому пользователю все наши продукты в первые 14 дней доступны совершенно бесплатно (кроме доп.услуг)",
|
||||
actualPrice: "0",
|
||||
},
|
||||
{
|
||||
name: "Месяц",
|
||||
type: "duration",
|
||||
description: "30 дней безлимитного пользования сервисом",
|
||||
actualPrice: "969",
|
||||
oldPrice: "1024",
|
||||
discount: "5",
|
||||
},
|
||||
{
|
||||
name: "3 месяца",
|
||||
type: "duration",
|
||||
description: "90 дней безлимитного пользования сервисом",
|
||||
actualPrice: " 2 325,6",
|
||||
oldPrice: "3060",
|
||||
discount: "24",
|
||||
},
|
||||
{
|
||||
name: "Год",
|
||||
type: "duration",
|
||||
description: "365 дней безлимитного пользования сервисом",
|
||||
actualPrice: " 7 501,84",
|
||||
oldPrice: "12 410",
|
||||
discount: "40",
|
||||
},
|
||||
{
|
||||
name: "3 года",
|
||||
type: "duration",
|
||||
description: "1095 дней безлимитного пользования сервисом",
|
||||
actualPrice: "16 939,65",
|
||||
oldPrice: "37 230",
|
||||
discount: "55",
|
||||
},
|
||||
{
|
||||
name: "100 Заявок",
|
||||
type: "requests",
|
||||
description: "Полное прохождение 100 опросов респондентом",
|
||||
actualPrice: "1 900",
|
||||
oldPrice: "2 000",
|
||||
discount: "5",
|
||||
},
|
||||
{
|
||||
name: "1 000 Заявок",
|
||||
type: "requests",
|
||||
description: "Полное прохождение 1000 опросов респондентом",
|
||||
actualPrice: "12 740",
|
||||
oldPrice: "2 000",
|
||||
discount: "36",
|
||||
},
|
||||
{
|
||||
name: "10 000 Заявок",
|
||||
type: "requests",
|
||||
description: "Полное прохождение 10000 опросов респондентом",
|
||||
actualPrice: "89 000",
|
||||
oldPrice: "200 000",
|
||||
discount: "56",
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<SectionStyled
|
||||
tag={"section"}
|
||||
bg={"#282937"}
|
||||
sxsect={{ marginTop: "-40px", padding: isMobile ? "0 16px" : isTablet ? "0 40px" : "0 20px" }}
|
||||
mwidth={"1160px"}
|
||||
sxcont={{
|
||||
boxSizing: "border-box",
|
||||
}}
|
||||
>
|
||||
<CssBaseline>
|
||||
<style>{swiperStyles}</style>
|
||||
</CssBaseline>
|
||||
<Box
|
||||
color="#ffffff"
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
flexWrap: "wrap",
|
||||
marginTop: "140px",
|
||||
marginBottom: "40px",
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" fontSize="36px" lineHeight={1}>
|
||||
Наши тарифы
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ marginBottom: "80px" }}>
|
||||
<Swiper
|
||||
slidesPerView={"auto"}
|
||||
spaceBetween={15}
|
||||
pagination={{
|
||||
clickable: true,
|
||||
}}
|
||||
modules={[Pagination, Navigation]}
|
||||
navigation={true}
|
||||
className="mySwiper"
|
||||
>
|
||||
{tariffs.map((tariff) => {
|
||||
return (
|
||||
<SwiperSlide style={{ width: isMobile ? "321px" : "360px" }}>
|
||||
<TariffCard
|
||||
name={tariff.name}
|
||||
type={tariff.type}
|
||||
description={tariff.description}
|
||||
actualPrice={tariff.actualPrice}
|
||||
discount={tariff.discount}
|
||||
oldPrice={tariff.oldPrice}
|
||||
/>
|
||||
</SwiperSlide>
|
||||
);
|
||||
})}
|
||||
</Swiper>
|
||||
</Box>
|
||||
</SectionStyled>
|
||||
);
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
||||
import { devlog } from "@frontend/kitui";
|
||||
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
|
||||
import { Box, Button } from "@mui/material";
|
||||
import { clearRuleForAll } from "@root/questions/actions";
|
||||
import { useQuestionsStore } from "@root/questions/store";
|
||||
import { updateRootContentId } from "@root/quizes/actions";
|
||||
@ -14,7 +14,6 @@ import {
|
||||
import { useUiTools } from "@root/uiTools/store";
|
||||
import type { Core } from "cytoscape";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
import { useEffect, useLayoutEffect, useMemo, useRef } from "react";
|
||||
import CytoscapeComponent from "react-cytoscapejs";
|
||||
import { withErrorBoundary } from "react-error-boundary";
|
||||
import { DeleteNodeModal } from "../DeleteNodeModal";
|
||||
@ -23,8 +22,15 @@ import { addNode, layoutOptions, storeToNodes } from "./helper";
|
||||
import { useRemoveNode } from "./hooks/useRemoveNode";
|
||||
import "./style/styles.css";
|
||||
import { stylesheet } from "./style/stylesheet";
|
||||
import { Box, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { InfoBanner } from "./InfoBanner/InfoBanner";
|
||||
import { PositionControl } from "./PositionControl/PositionControl";
|
||||
import { ZoomControl } from "./ZoomControl/ZoomControl";
|
||||
|
||||
function CsComponent() {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(650));
|
||||
const [isBannerVisible, setBannerVisible] = useState(true);
|
||||
const desireToOpenABranchingModal = useUiTools((state) => state.desireToOpenABranchingModal);
|
||||
const modalQuestionParentContentId = useUiTools((state) => state.modalQuestionParentContentId);
|
||||
const modalQuestionTargetContentId = useUiTools((state) => state.modalQuestionTargetContentId);
|
||||
@ -82,37 +88,25 @@ function CsComponent() {
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box mb="20px">
|
||||
<Button
|
||||
sx={{
|
||||
height: "27px",
|
||||
color: "#7E2AEA",
|
||||
textDecoration: "underline",
|
||||
fontSize: "16px",
|
||||
}}
|
||||
variant="text"
|
||||
onClick={() => {
|
||||
cyRef.current?.fit(undefined, 70);
|
||||
}}
|
||||
>
|
||||
Выровнять
|
||||
</Button>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
position: "relative",
|
||||
height: "480px",
|
||||
background: "#F2F3F7",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<CsNodeButtons csElements={csElements} cyRef={cyRef} />
|
||||
<Box sx={{ position: "relative" }}>
|
||||
{isBannerVisible && <InfoBanner setBannerVisible={setBannerVisible} />}
|
||||
<PositionControl cyRef={cyRef} />
|
||||
<ZoomControl cyRef={cyRef} />
|
||||
<CytoscapeComponent
|
||||
wheelSensitivity={0.1}
|
||||
elements={csElements}
|
||||
style={{
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
height: isMobile ? "327px" : "481px",
|
||||
background: "#F2F3F7",
|
||||
overflow: "hidden",
|
||||
borderRadius: "12px",
|
||||
width: "100%",
|
||||
}}
|
||||
stylesheet={stylesheet}
|
||||
layout={layoutOptions}
|
||||
@ -123,10 +117,9 @@ function CsComponent() {
|
||||
autounselectify={true}
|
||||
boxSelectionEnabled={false}
|
||||
/>
|
||||
<CsNodeButtons csElements={csElements} cyRef={cyRef} />
|
||||
</Box>
|
||||
<DeleteNodeModal removeNode={removeNode} />
|
||||
</>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -8,14 +8,29 @@ import {
|
||||
updateOpenedModalSettingsId,
|
||||
} from "@root/uiTools/actions";
|
||||
import { Core, EventObject, NodeSingular } from "cytoscape";
|
||||
import { MutableRefObject, forwardRef, useEffect, useMemo, useRef } from "react";
|
||||
import { addNode, isElementANode, isNodeInViewport, isQuestionProhibited, storeToNodes } from "./helper";
|
||||
import {
|
||||
forwardRef,
|
||||
MutableRefObject,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import {
|
||||
canAddChildToQuestion,
|
||||
isElementANode,
|
||||
isNodeInViewport,
|
||||
isQuestionProhibited,
|
||||
storeToNodes,
|
||||
} from "./helper";
|
||||
|
||||
const csButtonTypes = ["delete", "add", "settings", "select"] as const;
|
||||
|
||||
type CsButtonType = (typeof csButtonTypes)[number];
|
||||
|
||||
type CsNodeButtonsByType = Partial<Record<CsButtonType, HTMLButtonElement | null>>;
|
||||
type CsNodeButtonsByType = Partial<
|
||||
Record<CsButtonType, HTMLButtonElement | null>
|
||||
>;
|
||||
|
||||
type CsButtonsById = Record<string, CsNodeButtonsByType | undefined>;
|
||||
|
||||
@ -29,7 +44,10 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
|
||||
|
||||
const buttons = useMemo(() => {
|
||||
const nodeElements = csElements.filter(isElementANode);
|
||||
buttonRefsById.current = nodeElements.reduce<CsButtonsById>((acc, node) => ((acc[node.data.id] = {}), acc), {});
|
||||
buttonRefsById.current = nodeElements.reduce<CsButtonsById>(
|
||||
(acc, node) => ((acc[node.data.id] = {}), acc),
|
||||
{},
|
||||
);
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
@ -38,10 +56,7 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
|
||||
left: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
pointerEvents: "none",
|
||||
"> *": {
|
||||
pointerEvents: "auto",
|
||||
},
|
||||
borderRadius: "12px",
|
||||
}}
|
||||
>
|
||||
{nodeElements.flatMap((csElement) => [
|
||||
@ -61,23 +76,24 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
|
||||
const buttonData = buttonRefsById.current[csElement.data.id];
|
||||
if (buttonData) buttonData.add = r;
|
||||
}}
|
||||
onPointerUp={() => {
|
||||
addNode({ parentNodeContentId: csElement.data.id });
|
||||
cleardragQuestionContentId();
|
||||
onClick={() => {
|
||||
setModalQuestionParentContentId(csElement.data.id);
|
||||
setOpenedModalQuestions(canAddChildToQuestion(csElement.data.id));
|
||||
}}
|
||||
/>,
|
||||
!csElement.data.isRoot && !isQuestionProhibited(csElement.data.qtype) && (
|
||||
<CsSettingsButton
|
||||
key={`settings-${csElement.data.id}`}
|
||||
ref={(r) => {
|
||||
const buttonData = buttonRefsById.current[csElement.data.id];
|
||||
if (buttonData) buttonData.settings = r;
|
||||
}}
|
||||
onClick={() => {
|
||||
updateOpenedModalSettingsId(csElement.data.id);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
!csElement.data.isRoot &&
|
||||
!isQuestionProhibited(csElement.data.qtype) && (
|
||||
<CsSettingsButton
|
||||
key={`settings-${csElement.data.id}`}
|
||||
ref={(r) => {
|
||||
const buttonData = buttonRefsById.current[csElement.data.id];
|
||||
if (buttonData) buttonData.settings = r;
|
||||
}}
|
||||
onClick={() => {
|
||||
updateOpenedModalSettingsId(csElement.data.id);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
//оболочка узла
|
||||
<CsSelectButton
|
||||
key={`select-${csElement.data.id}`}
|
||||
@ -87,7 +103,7 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
|
||||
}}
|
||||
onClick={() => {
|
||||
setModalQuestionParentContentId(csElement.data.id);
|
||||
setOpenedModalQuestions(!(isQuestionProhibited(csElement.data.type) && csElement.data.children > 0));
|
||||
setOpenedModalQuestions(canAddChildToQuestion(csElement.data.id));
|
||||
}}
|
||||
/>,
|
||||
])}
|
||||
@ -130,7 +146,10 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
|
||||
};
|
||||
}, []);
|
||||
|
||||
return buttons;
|
||||
const container = cyRef.current?.container();
|
||||
const buttonsPortal = container ? createPortal(buttons, container) : null;
|
||||
|
||||
return buttonsPortal;
|
||||
}
|
||||
|
||||
const applyButtonStyleByType: Record<
|
||||
@ -139,8 +158,10 @@ const applyButtonStyleByType: Record<
|
||||
> = {
|
||||
delete(button, node, zoom) {
|
||||
const nodePosition = node.renderedPosition();
|
||||
const shiftX = node.renderedWidth() / 2 - (CLOSE_BUTTON_WIDTH / 2 + 6) * zoom;
|
||||
const shiftY = node.renderedHeight() / 2 - (CLOSE_BUTTON_HEIGHT / 2 + 6) * zoom;
|
||||
const shiftX =
|
||||
node.renderedWidth() / 2 - (CLOSE_BUTTON_WIDTH / 2 + 6) * zoom;
|
||||
const shiftY =
|
||||
node.renderedHeight() / 2 - (CLOSE_BUTTON_HEIGHT / 2 + 6) * zoom;
|
||||
|
||||
if (!isNodeInViewport(node, 100)) {
|
||||
return button.style.setProperty("display", "none");
|
||||
@ -151,12 +172,13 @@ const applyButtonStyleByType: Record<
|
||||
button.style.setProperty("top", `${nodePosition.y}px`);
|
||||
button.style.setProperty(
|
||||
"transform",
|
||||
`translate3d(calc(-50% + ${shiftX}px), calc(-50% - ${shiftY}px), 0) scale(${zoom})`
|
||||
`translate3d(calc(-50% + ${shiftX}px), calc(-50% - ${shiftY}px), 0) scale(${zoom})`,
|
||||
);
|
||||
},
|
||||
add(button, node, zoom) {
|
||||
const nodePosition = node.renderedPosition();
|
||||
const shiftX = node.renderedWidth() / 2 + (ADD_BUTTON_WIDTH / 2) * zoom;
|
||||
const shiftX =
|
||||
node.renderedWidth() / 2 + (ADD_BUTTON_WIDTH / 2 - 10) * zoom;
|
||||
|
||||
if (!isNodeInViewport(node, 100)) {
|
||||
return button.style.setProperty("display", "none");
|
||||
@ -165,11 +187,15 @@ const applyButtonStyleByType: Record<
|
||||
button.style.setProperty("display", "flex");
|
||||
button.style.setProperty("left", `${nodePosition.x}px`);
|
||||
button.style.setProperty("top", `${nodePosition.y}px`);
|
||||
button.style.setProperty("transform", `translate3d(calc(-50% + ${shiftX}px), -50%, 0) scale(${zoom})`);
|
||||
button.style.setProperty(
|
||||
"transform",
|
||||
`translate3d(calc(-50% + ${shiftX}px), -50%, 0) scale(${zoom})`,
|
||||
);
|
||||
},
|
||||
settings(button, node, zoom) {
|
||||
const nodePosition = node.renderedPosition();
|
||||
const shiftX = -node.renderedWidth() / 2 - (SETTINGS_BUTTON_WIDTH / 2) * zoom;
|
||||
const shiftX =
|
||||
-node.renderedWidth() / 2 - (SETTINGS_BUTTON_WIDTH / 2) * zoom;
|
||||
|
||||
if (!isNodeInViewport(node, 100)) {
|
||||
return button.style.setProperty("display", "none");
|
||||
@ -178,7 +204,10 @@ const applyButtonStyleByType: Record<
|
||||
button.style.setProperty("display", "flex");
|
||||
button.style.setProperty("left", `${nodePosition.x}px`);
|
||||
button.style.setProperty("top", `${nodePosition.y}px`);
|
||||
button.style.setProperty("transform", `translate3d(calc(-50% + ${shiftX}px), -50%, 0) scale(${zoom})`);
|
||||
button.style.setProperty(
|
||||
"transform",
|
||||
`translate3d(calc(-50% + ${shiftX}px), -50%, 0) scale(${zoom})`,
|
||||
);
|
||||
},
|
||||
select(button, node, zoom) {
|
||||
const nodePosition = node.renderedPosition();
|
||||
@ -190,7 +219,10 @@ const applyButtonStyleByType: Record<
|
||||
button.style.setProperty("display", "flex");
|
||||
button.style.setProperty("left", `${nodePosition.x}px`);
|
||||
button.style.setProperty("top", `${nodePosition.y}px`);
|
||||
button.style.setProperty("transform", `translate3d(-50%, -50%, 0) scale(${zoom})`);
|
||||
button.style.setProperty(
|
||||
"transform",
|
||||
`translate3d(-50%, -50%, 0) scale(${zoom})`,
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
@ -233,9 +265,9 @@ const ADD_BUTTON_HEIGHT = ADD_BUTTON_WIDTH;
|
||||
const CsAddButton = forwardRef<
|
||||
HTMLButtonElement,
|
||||
{
|
||||
onPointerUp: () => void;
|
||||
onClick: () => void;
|
||||
}
|
||||
>(({ onPointerUp }, ref) => (
|
||||
>(({ onClick }, ref) => (
|
||||
<IconButton
|
||||
ref={ref}
|
||||
sx={{
|
||||
@ -252,7 +284,7 @@ const CsAddButton = forwardRef<
|
||||
backgroundColor: "#f9f9fc",
|
||||
},
|
||||
}}
|
||||
onPointerUp={onPointerUp}
|
||||
onClick={onClick}
|
||||
onMouseDownCapture={(event) => event.stopPropagation()}
|
||||
onTouchStartCapture={(event) => event.stopPropagation()}
|
||||
>
|
||||
@ -260,8 +292,8 @@ const CsAddButton = forwardRef<
|
||||
</IconButton>
|
||||
));
|
||||
|
||||
const SETTINGS_BUTTON_WIDTH = 70;
|
||||
const SETTINGS_BUTTON_HEIGHT = 60;
|
||||
const SETTINGS_BUTTON_WIDTH = 50;
|
||||
const SETTINGS_BUTTON_HEIGHT = 40;
|
||||
|
||||
const CsSettingsButton = forwardRef<
|
||||
HTMLButtonElement,
|
||||
@ -329,7 +361,8 @@ const CsSelectButton = forwardRef<
|
||||
width: SELECT_BUTTON_WIDTH,
|
||||
height: SELECT_BUTTON_HEIGHT,
|
||||
backgroundColor: "rgb(0 0 0 / 0)",
|
||||
borderRadius: "8px",
|
||||
border: "1px solid #9A9AAF",
|
||||
borderRadius: "6px",
|
||||
p: 0,
|
||||
zIndex: 0,
|
||||
}}
|
||||
|
@ -1,4 +1,10 @@
|
||||
import { Box } from "@mui/material";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import {
|
||||
clearRuleForAll,
|
||||
createResult,
|
||||
@ -14,8 +20,11 @@ import {
|
||||
import { useUiTools } from "@root/uiTools/store";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
import { useEffect, useLayoutEffect, useRef } from "react";
|
||||
import { GrayPlus } from "@icons/questionsPage/GrayPlus";
|
||||
|
||||
export const FirstNodeField = () => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(650));
|
||||
const quiz = useCurrentQuiz();
|
||||
const modalQuestionTargetContentId = useUiTools(
|
||||
(state) => state.modalQuestionTargetContentId,
|
||||
@ -80,17 +89,49 @@ export const FirstNodeField = () => {
|
||||
<Box
|
||||
ref={Container}
|
||||
sx={{
|
||||
height: "100%",
|
||||
height: isMobile ? "327px" : "481px",
|
||||
width: "100%",
|
||||
backgroundColor: "#f2f3f7",
|
||||
backgroundColor: theme.palette.background.default,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
color: "#4d4d4d",
|
||||
color: theme.palette.grey3.main,
|
||||
fontSize: "50px",
|
||||
borderRadius: "12px",
|
||||
padding: "20px",
|
||||
}}
|
||||
>
|
||||
+
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: "20px",
|
||||
width: "275px",
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
color: theme.palette.grey2.main,
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
Добавьте созданные вопросы и настройте связи между ними
|
||||
</Typography>
|
||||
<Button
|
||||
sx={{
|
||||
width: "70px",
|
||||
height: "70px",
|
||||
borderRadius: "12px",
|
||||
background: "rgba(154, 154, 175, 0.09)",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<GrayPlus />
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
99
src/pages/Questions/BranchingMap/InfoBanner/InfoBanner.tsx
Normal file
99
src/pages/Questions/BranchingMap/InfoBanner/InfoBanner.tsx
Normal file
@ -0,0 +1,99 @@
|
||||
import {
|
||||
Box,
|
||||
IconButton,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { Add } from "@mui/icons-material";
|
||||
import { EditIcon } from "@icons/questionsPage/EditIcon";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { Dispatch, FC, SetStateAction } from "react";
|
||||
|
||||
type InfoBannerProps = {
|
||||
setBannerVisible: Dispatch<SetStateAction<boolean>>;
|
||||
};
|
||||
|
||||
export const InfoBanner: FC<InfoBannerProps> = ({ setBannerVisible }) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(650));
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: "30px",
|
||||
right: "30px",
|
||||
padding: "20px",
|
||||
borderRadius: "12px",
|
||||
background: "#fff",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
zIndex: 2,
|
||||
boxShadow: "0 0 20px rgba(0, 0, 0, 0.15)",
|
||||
animation: "fadeIn 0.5s",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
maxWidth: isMobile ? "253px" : "345px",
|
||||
color: "#9A9AAF",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "10px",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between" }}>
|
||||
<Typography>Добавьте больше вопросов кнопкой</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
width: "20px",
|
||||
height: "20px",
|
||||
color: "rgba(154, 154, 175, 0.5)",
|
||||
backgroundColor: "#eeeff4",
|
||||
borderRadius: "6px",
|
||||
border: "1.5px dashed rgba(154, 154, 175, 0.5)",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Add fontSize={"small"} />
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography>
|
||||
Настраивайте условия их отображения в квизе с помощью
|
||||
</Typography>
|
||||
<EditIcon />
|
||||
</Box>
|
||||
</Box>
|
||||
<IconButton
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: "-10px",
|
||||
right: "-10px",
|
||||
width: "30px",
|
||||
height: "30px",
|
||||
background: "#4D4D4D",
|
||||
opacity: "0.2",
|
||||
BorderRadius: "50%",
|
||||
color: "#fff",
|
||||
"&:hover": {
|
||||
background: "black",
|
||||
},
|
||||
}}
|
||||
onClick={() => setBannerVisible(false)}
|
||||
>
|
||||
<CloseIcon fontSize={"medium"} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
);
|
||||
};
|
@ -0,0 +1,64 @@
|
||||
import { Box, Button, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { ExpandIcon } from "@icons/questionsPage/ExpandIcon";
|
||||
import { AlignIcon } from "@icons/questionsPage/AlignIcon";
|
||||
import { FC, MutableRefObject } from "react";
|
||||
import { Core } from "cytoscape";
|
||||
|
||||
type PositionControlProps = {
|
||||
cyRef: MutableRefObject<Core | null>;
|
||||
};
|
||||
|
||||
export const PositionControl: FC<PositionControlProps> = ({ cyRef }) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(650));
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
bottom: isMobile ? "15px" : "20px",
|
||||
left: isMobile ? "15px" : "20px",
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minWidth: "36px",
|
||||
width: "36px",
|
||||
height: "36px",
|
||||
background: "#9A9AAF",
|
||||
opacity: "0.7",
|
||||
zIndex: 2,
|
||||
}}
|
||||
onClick={() => {
|
||||
cyRef.current?.zoom(1);
|
||||
cyRef.current?.center();
|
||||
}}
|
||||
>
|
||||
<ExpandIcon />
|
||||
</Button>
|
||||
<Button
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minWidth: "36px",
|
||||
width: "36px",
|
||||
height: "36px",
|
||||
background: "#9A9AAF",
|
||||
opacity: "0.7",
|
||||
zIndex: 2,
|
||||
}}
|
||||
onClick={() => {
|
||||
cyRef.current?.fit(undefined, 70);
|
||||
}}
|
||||
>
|
||||
<AlignIcon />
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
};
|
72
src/pages/Questions/BranchingMap/ZoomControl/ZoomControl.tsx
Normal file
72
src/pages/Questions/BranchingMap/ZoomControl/ZoomControl.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import { Box, Button, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { FC, MutableRefObject } from "react";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import RemoveIcon from "@mui/icons-material/Remove";
|
||||
import { Core } from "cytoscape";
|
||||
|
||||
type PositionControlProps = {
|
||||
cyRef: MutableRefObject<Core | null>;
|
||||
};
|
||||
|
||||
export const ZoomControl: FC<PositionControlProps> = ({ cyRef }) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(650));
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
bottom: isMobile ? "15px" : "20px",
|
||||
right: isMobile ? "15px" : "20px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "10px",
|
||||
background: "#EEE4FC",
|
||||
padding: "16px",
|
||||
borderRadius: "8px",
|
||||
zIndex: 2,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minWidth: "36px",
|
||||
width: "36px",
|
||||
height: "36px",
|
||||
background: "#7E2AEA",
|
||||
fontSize: "16px",
|
||||
color: "#fff",
|
||||
zIndex: 2,
|
||||
}}
|
||||
onClick={() => {
|
||||
const currentZoom = cyRef.current?.zoom() || 1;
|
||||
cyRef.current?.zoom(currentZoom + 0.1);
|
||||
}}
|
||||
>
|
||||
<AddIcon />
|
||||
</Button>
|
||||
<Button
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minWidth: "36px",
|
||||
width: "36px",
|
||||
height: "36px",
|
||||
background: "#7E2AEA",
|
||||
fontSize: "16px",
|
||||
color: "#fff",
|
||||
zIndex: 2,
|
||||
}}
|
||||
onClick={() => {
|
||||
const currentZoom = cyRef.current?.zoom() || 1;
|
||||
cyRef.current?.zoom(currentZoom - 0.1);
|
||||
}}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
};
|
@ -1,4 +1,3 @@
|
||||
import { QuestionType } from "@model/question/question";
|
||||
import { QuizQuestionResult } from "@model/questionTypes/result";
|
||||
import {
|
||||
AnyTypedQuizQuestion,
|
||||
@ -66,7 +65,8 @@ export const storeToNodes = (questions: AnyTypedQuizQuestion[]) => {
|
||||
question.title === "" || question.title === " "
|
||||
? "noname"
|
||||
: question.title;
|
||||
if (label.length > 10) label = label.slice(0, 10).toLowerCase() + "…";
|
||||
label = label.trim().replace(/\s+/g, " ");
|
||||
if (label.length > 20) label = label.slice(0, 20).toLowerCase() + "…";
|
||||
|
||||
nodes.push({
|
||||
data: {
|
||||
@ -307,7 +307,7 @@ export function calcNodePosition(node: any) {
|
||||
const width = n.data("subtreeWidth");
|
||||
|
||||
n.data("oldPos", {
|
||||
x: 250 * n.data("layer"),
|
||||
x: 350 * n.data("layer"),
|
||||
y: yoffset + width / 2,
|
||||
});
|
||||
yoffset += width;
|
||||
@ -326,6 +326,21 @@ export function calcNodePosition(node: any) {
|
||||
}
|
||||
}
|
||||
|
||||
export const canAddChildToQuestion = (parentNodeContentId: string) => {
|
||||
const parentQuestion = {
|
||||
...getQuestionByContentId(parentNodeContentId),
|
||||
} as AnyTypedQuizQuestion;
|
||||
if (
|
||||
parentQuestion.type !== undefined &&
|
||||
isQuestionProhibited(parentQuestion.type) &&
|
||||
parentQuestion.content.rule.children.length > 0
|
||||
) {
|
||||
enqueueSnackbar("У вопроса этого типа может быть только 1 потомок");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export const addNode = ({
|
||||
parentNodeContentId,
|
||||
targetNodeContentId,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Box } from "@mui/material";
|
||||
import { Box, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import { useUiTools } from "@root/uiTools/store";
|
||||
import { BranchingQuestionsModal } from "../BranchingQuestionsModal";
|
||||
@ -6,6 +6,8 @@ import CsComponent from "./CsComponent";
|
||||
import { FirstNodeField } from "./FirstNodeField";
|
||||
|
||||
export const BranchingMap = () => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(650));
|
||||
const quiz = useCurrentQuiz();
|
||||
const dragQuestionContentId = useUiTools((state) => state.dragQuestionContentId);
|
||||
|
||||
@ -13,13 +15,15 @@ export const BranchingMap = () => {
|
||||
<Box
|
||||
sx={{
|
||||
overflow: "hidden",
|
||||
padding: "20px",
|
||||
background: "#FFFFFF",
|
||||
padding: isMobile ? "15px" : "20px",
|
||||
background: theme.palette.common.white,
|
||||
borderRadius: "12px",
|
||||
boxShadow: "0px 8px 24px rgba(210, 208, 225, 0.4)",
|
||||
marginBottom: "40px",
|
||||
height: "568px",
|
||||
border: dragQuestionContentId === null ? "none" : "#7e2aea 2px dashed",
|
||||
width: "100%",
|
||||
border:
|
||||
dragQuestionContentId === null
|
||||
? "none"
|
||||
: `${theme.palette.brightPurple.main} 2px dashed`,
|
||||
}}
|
||||
>
|
||||
{quiz?.config.haveRoot ? <CsComponent /> : <FirstNodeField />}
|
||||
|
@ -9,13 +9,14 @@ export const stylesheet: Stylesheet[] = [
|
||||
height: 130,
|
||||
backgroundColor: "#FFFFFF",
|
||||
label: "data(label)",
|
||||
"font-size": "16",
|
||||
"font-size": "12",
|
||||
color: "#4D4D4D",
|
||||
"text-halign": "center",
|
||||
"text-halign": "right",
|
||||
"text-valign": "center",
|
||||
"text-wrap": "wrap",
|
||||
"text-max-width": "130px",
|
||||
"text-overflow-wrap": "whitespace",
|
||||
"text-margin-x": -115,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -40,7 +41,7 @@ export const stylesheet: Stylesheet[] = [
|
||||
"line-color": "#DEDFE7",
|
||||
"curve-style": "taxi",
|
||||
"taxi-direction": "horizontal",
|
||||
"taxi-turn": 60,
|
||||
"taxi-turn": 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1,34 +1,26 @@
|
||||
import { useState, useRef, useEffect, useLayoutEffect } from "react";
|
||||
import { useLayoutEffect, useState } from "react";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
FormControl,
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
Link,
|
||||
Modal,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Tooltip,
|
||||
Typography,
|
||||
useTheme,
|
||||
Checkbox,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import {
|
||||
AnyTypedQuizQuestion,
|
||||
createBranchingRuleMain,
|
||||
} from "../../../model/questionTypes/shared";
|
||||
import { Select } from "../Select";
|
||||
|
||||
import RadioCheck from "@ui_kit/RadioCheck";
|
||||
import RadioIcon from "@ui_kit/RadioIcon";
|
||||
import InfoIcon from "@icons/Info";
|
||||
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
||||
|
||||
import { TypeSwitch, BlockRule } from "./Settings";
|
||||
import { TypeSwitch } from "./Settings";
|
||||
import {
|
||||
getQuestionById,
|
||||
getQuestionByContentId,
|
||||
getQuestionById,
|
||||
updateQuestion,
|
||||
} from "@root/questions/actions";
|
||||
import { updateOpenedModalSettingsId } from "@root/uiTools/actions";
|
||||
@ -101,7 +93,7 @@ export default function BranchingQuestions() {
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
maxWidth: "620px",
|
||||
width: "100%",
|
||||
width: "90%",
|
||||
bgcolor: "background.paper",
|
||||
borderRadius: "12px",
|
||||
boxShadow: 24,
|
||||
@ -114,30 +106,30 @@ export default function BranchingQuestions() {
|
||||
boxSizing: "border-box",
|
||||
background: "#F2F3F7",
|
||||
height: "70px",
|
||||
padding: "0 25px",
|
||||
padding: "25px 20px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
color: "#9A9AAF",
|
||||
gap: "10px",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ color: "#4d4d4d" }}>
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
maxWidth: isSmallMobile
|
||||
? "250px"
|
||||
: isMobile
|
||||
? "350px"
|
||||
: "450px",
|
||||
display: "inline-block",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{targetQuestion.title}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography
|
||||
component="span"
|
||||
sx={{
|
||||
lineHeight: "1",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
maxWidth: isSmallMobile
|
||||
? "250px"
|
||||
: isMobile
|
||||
? "350px"
|
||||
: "450px",
|
||||
display: "inline-block",
|
||||
}}
|
||||
>
|
||||
{targetQuestion.title}
|
||||
</Typography>
|
||||
{isMobile ? (
|
||||
<TooltipClickInfo
|
||||
title={
|
||||
@ -150,7 +142,7 @@ export default function BranchingQuestions() {
|
||||
placement="top"
|
||||
>
|
||||
<Box>
|
||||
<InfoIcon />
|
||||
<InfoIcon sx={{ padding: 0 }} />
|
||||
</Box>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
@ -1,4 +1,14 @@
|
||||
import { Box, Modal, Button, Typography } from "@mui/material";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
FormControlLabel,
|
||||
Modal,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { useQuestionsStore } from "@root/questions/store";
|
||||
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
|
||||
import { useUiTools } from "@root/uiTools/store";
|
||||
@ -6,12 +16,20 @@ import {
|
||||
setModalQuestionTargetContentId,
|
||||
setOpenedModalQuestions,
|
||||
} from "@root/uiTools/actions";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import RadioCheck from "@ui_kit/RadioCheck";
|
||||
import RadioIcon from "@ui_kit/RadioIcon";
|
||||
import { RoundedCheckedIcon } from "@icons/questionsPage/RoundedCheckedIcon";
|
||||
|
||||
export const BranchingQuestionsModal = () => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(650));
|
||||
|
||||
const trashQuestions = useQuestionsStore().questions;
|
||||
const questions = trashQuestions.filter(
|
||||
(question) => question.type !== "result",
|
||||
);
|
||||
|
||||
const openedModalQuestions = useUiTools(
|
||||
(state) => state.openedModalQuestions,
|
||||
);
|
||||
@ -21,14 +39,30 @@ export const BranchingQuestionsModal = () => {
|
||||
};
|
||||
|
||||
const typedQuestions: AnyTypedQuizQuestion[] = questions.filter(
|
||||
(question) =>
|
||||
question.type &&
|
||||
!question.content.rule.parentId &&
|
||||
question.type !== "result",
|
||||
(question) => question.type && question.type !== "result",
|
||||
) as AnyTypedQuizQuestion[];
|
||||
|
||||
if (typedQuestions.length === 0) return <></>;
|
||||
|
||||
const [selectedQuestion, setSelectedQuestion] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (openedModalQuestions) {
|
||||
setSelectedQuestion(null);
|
||||
}
|
||||
}, [openedModalQuestions]);
|
||||
|
||||
const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSelectedQuestion(event.target.value);
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
if (selectedQuestion) {
|
||||
setModalQuestionTargetContentId(selectedQuestion);
|
||||
}
|
||||
handleClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal open={openedModalQuestions} onClose={handleClose}>
|
||||
<Box
|
||||
@ -39,48 +73,91 @@ export const BranchingQuestionsModal = () => {
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
maxWidth: "620px",
|
||||
width: "100%",
|
||||
width: "90%",
|
||||
bgcolor: "background.paper",
|
||||
borderRadius: "12px",
|
||||
boxShadow: 24,
|
||||
padding: "30px 0",
|
||||
height: "80vh",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ margin: "0 auto", maxWidth: "350px" }}>
|
||||
{typedQuestions.map((question) => (
|
||||
<Button
|
||||
<Box
|
||||
sx={{ width: "100%", background: theme.palette.background.default }}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
padding: "25px 0 25px 20px",
|
||||
color: theme.palette.grey2.main,
|
||||
}}
|
||||
>
|
||||
Выберите вопрос, который вы хотите добавить в ветвление
|
||||
</Typography>
|
||||
</Box>
|
||||
<RadioGroup
|
||||
value={selectedQuestion}
|
||||
onChange={handleRadioChange}
|
||||
sx={{
|
||||
height: "346px",
|
||||
width: "100%",
|
||||
overflow: "auto",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flexWrap: "nowrap",
|
||||
}}
|
||||
>
|
||||
{typedQuestions.map((question, index) => (
|
||||
<FormControlLabel
|
||||
key={question.content.id}
|
||||
onClick={() => {
|
||||
setModalQuestionTargetContentId(question.content.id);
|
||||
handleClose();
|
||||
}}
|
||||
value={question.content.id}
|
||||
control={
|
||||
<Radio
|
||||
checkedIcon={<RadioCheck />}
|
||||
icon={
|
||||
question.content.rule.parentId ? (
|
||||
<RoundedCheckedIcon />
|
||||
) : (
|
||||
<RadioIcon />
|
||||
)
|
||||
}
|
||||
/>
|
||||
}
|
||||
label={question.title || "нет заголовка"}
|
||||
disabled={!!question.content.rule.parentId}
|
||||
sx={{
|
||||
padding: "8px 12px",
|
||||
margin: 0,
|
||||
width: "100%",
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
padding: "12px",
|
||||
background: "#FFFFFF",
|
||||
borderRadius: "8px",
|
||||
marginBottom: "20px",
|
||||
boxShadow: "0px 10px 30px #e7e7e7",
|
||||
backgroundImage: `url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' rx='8' ry='8' stroke='rgb(154, 154, 175)' strokeWidth='2' stroke-dasharray='8 8' stroke-dashoffset='0' strokeLinecap='square'/%3e%3c/svg%3e");
|
||||
border-radius: 8px;`,
|
||||
"&:last-child": { marginBottom: 0 },
|
||||
backgroundColor:
|
||||
index % 2 === 0
|
||||
? theme.palette.common.white
|
||||
: "rgba(242, 243, 247, 0.5)",
|
||||
color: theme.palette.grey3.main,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
width: "100%",
|
||||
color: "#000",
|
||||
}}
|
||||
>
|
||||
{question.title || "нет заголовка"}
|
||||
</Typography>
|
||||
</Button>
|
||||
/>
|
||||
))}
|
||||
</RadioGroup>
|
||||
<Box
|
||||
sx={{
|
||||
margin: "20px",
|
||||
width: "auto",
|
||||
display: "flex",
|
||||
justifyContent: isMobile ? "space-between" : "end",
|
||||
gap: "10px",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
sx={{ width: isMobile ? "150px" : "130px", height: "44px" }}
|
||||
onClick={handleClose}
|
||||
variant={"outlined"}
|
||||
>
|
||||
Отмена
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
sx={{ width: isMobile ? "150px" : "130px", height: "44px" }}
|
||||
variant={"contained"}
|
||||
onClick={handleConfirm}
|
||||
>
|
||||
Готово
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Modal>
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { Box, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { Box, Skeleton, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { deleteTimeoutedQuestions } from "@utils/deleteTimeoutedQuestions";
|
||||
import { useCallback } from "react";
|
||||
import { BranchingMap } from "./BranchingMap";
|
||||
import { lazy, Suspense, useCallback } from "react";
|
||||
import { DraggableList } from "./DraggableList";
|
||||
import { SwitchBranchingPanel } from "./SwitchBranchingPanel";
|
||||
|
||||
const BranchingMap = lazy(() =>
|
||||
import("./BranchingMap").then((module) => ({ default: module.BranchingMap })),
|
||||
);
|
||||
interface Props {
|
||||
openBranchingPage: boolean;
|
||||
setOpenBranchingPage: (a: boolean) => void;
|
||||
@ -18,6 +20,7 @@ export const QuestionSwitchWindowTool = ({
|
||||
}: Props) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||
|
||||
const openBranchingPageHC = useCallback(() => {
|
||||
if (!openBranchingPage) {
|
||||
@ -30,14 +33,26 @@ export const QuestionSwitchWindowTool = ({
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "20px",
|
||||
flexWrap: "wrap",
|
||||
marginBottom: isMobile ? "20px" : undefined,
|
||||
marginBottom: isMobile ? "25px" : "30px",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ flexBasis: "796px" }}>
|
||||
<Box sx={{ width: isTablet ? "100%" : "796px" }}>
|
||||
{openBranchingPage ? (
|
||||
<BranchingMap />
|
||||
<Suspense
|
||||
fallback={
|
||||
<Skeleton
|
||||
sx={{
|
||||
maxWidth: "796px",
|
||||
width: "100%",
|
||||
height: isMobile ? "357px" : "521px",
|
||||
transform: "none",
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<BranchingMap />
|
||||
</Suspense>
|
||||
) : (
|
||||
<DraggableList
|
||||
openBranchingPage={openBranchingPage}
|
||||
|
@ -1,4 +1,11 @@
|
||||
import { Box, Button, IconButton, Typography, useTheme } from "@mui/material";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
IconButton,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import {
|
||||
collapseAllQuestions,
|
||||
createUntypedQuestion,
|
||||
@ -11,7 +18,7 @@ import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import { updateEditSomeQuestion } from "@root/uiTools/actions";
|
||||
import { useUiTools } from "@root/uiTools/store";
|
||||
import QuizPreview from "@ui_kit/QuizPreview/QuizPreview";
|
||||
import { useLayoutEffect, useRef } from "react";
|
||||
import { useLayoutEffect } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import AddPlus from "../../assets/icons/questionsPage/addPlus";
|
||||
import ArrowLeft from "../../assets/icons/questionsPage/arrowLeft";
|
||||
@ -30,6 +37,7 @@ export default function QuestionsPage({
|
||||
widthMain,
|
||||
}: Props) {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(650));
|
||||
const { openedModalSettingsId } = useUiTools();
|
||||
const quiz = useCurrentQuiz();
|
||||
useLayoutEffect(() => {
|
||||
@ -47,7 +55,7 @@ export default function QuestionsPage({
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
margin: "60px 0 40px 0",
|
||||
margin: isMobile ? "25px 0" : "40px 0",
|
||||
}}
|
||||
>
|
||||
<Typography variant={"h5"} sx={{ wordBreak: "break-word" }}>
|
||||
|
@ -1,14 +1,6 @@
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
Switch,
|
||||
useTheme,
|
||||
Button,
|
||||
useMediaQuery,
|
||||
} from "@mui/material";
|
||||
|
||||
import { QuestionsList } from "./QuestionsList";
|
||||
import { Box, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { PanelSwitchQuestionListGraph } from "@ui_kit/Toolbars/PanelSwitchQuestionListGraph";
|
||||
|
||||
interface Props {
|
||||
openBranchingPage: boolean;
|
||||
setOpenBranchingPage: () => void;
|
||||
@ -31,9 +23,6 @@ export const SwitchBranchingPanel = ({
|
||||
setOpenBranchingPage={setOpenBranchingPage}
|
||||
/>
|
||||
)}
|
||||
{openBranchingPage && (
|
||||
<QuestionsList setOpenBranchingPage={setOpenBranchingPage} />
|
||||
)}
|
||||
</Box>
|
||||
) : (
|
||||
<></>
|
||||
|
@ -177,7 +177,7 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
|
||||
gap: isMobile ? "5px" : "15px",
|
||||
background: "#FFF",
|
||||
borderTop: "#f2f3f7 2px solid",
|
||||
zIndex: 1,
|
||||
zIndex: 3,
|
||||
position: isMobile ? "fixed" : undefined,
|
||||
bottom: isMobile ? 0 : undefined,
|
||||
}}
|
||||
|
@ -4,7 +4,7 @@ interface Props {
|
||||
sx?: SxProps<Theme>;
|
||||
}
|
||||
|
||||
export default function BannerWidgetPreviewIcon({ sx = [] }: Props) {
|
||||
export default function TaskIcon({ sx = [] }: Props) {
|
||||
return (
|
||||
<Box
|
||||
sx={[
|
||||
@ -13,6 +13,7 @@ export default function BannerWidgetPreviewIcon({ sx = [] }: Props) {
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexShrink: 0,
|
||||
color: "white",
|
||||
"& svg": {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
@ -21,31 +22,35 @@ export default function BannerWidgetPreviewIcon({ sx = [] }: Props) {
|
||||
...(Array.isArray(sx) ? sx : [sx]),
|
||||
]}
|
||||
>
|
||||
<svg viewBox="0 0 20 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg
|
||||
viewBox="0 0 20 19"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M13.2979 2.94922H15.4949C15.6488 2.94922 15.7964 3.01036 15.9052 3.11919C16.0141 3.22802 16.0752 3.37563 16.0752 3.52954V6.77848M7.21163 2.94922H5.04907C4.89516 2.94922 4.74755 3.01036 4.63872 3.11919C4.52989 3.22802 4.46875 3.37563 4.46875 3.52954V15.7163C4.46875 15.8702 4.52989 16.0178 4.63872 16.1267C4.74755 16.2355 4.89516 16.2966 5.04907 16.2966H8.53802M7.95068 16.2966H15.4949C15.6488 16.2966 15.7964 16.2355 15.9052 16.1267C16.0141 16.0178 16.0752 15.8702 16.0752 15.7163V11.9923"
|
||||
stroke="white"
|
||||
stroke="currentColor"
|
||||
strokeWidth="0.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M9.40182 13.7891H7.65735C7.58039 13.7891 7.50659 13.762 7.45217 13.7139C7.39776 13.6659 7.36719 13.6006 7.36719 13.5326V8.14708C7.36719 8.07906 7.39776 8.01383 7.45217 7.96574C7.50659 7.91764 7.58039 7.89062 7.65735 7.89062H9.10815H12.8802C12.9572 7.89062 13.031 7.91764 13.0854 7.96574C13.1398 8.01383 13.1704 8.07906 13.1704 8.14708V9.58283"
|
||||
stroke="white"
|
||||
stroke="currentColor"
|
||||
strokeWidth="0.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M7.36719 1.8125H13.1704V3.39705C13.1704 3.71756 12.9106 3.97737 12.5901 3.97737H7.94751C7.62701 3.97737 7.36719 3.71756 7.36719 3.39705V1.8125Z"
|
||||
stroke="white"
|
||||
stroke="currentColor"
|
||||
strokeWidth="0.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M17.0844 8.36719L11.8615 13.5901L9.25 10.9786"
|
||||
stroke="white"
|
||||
stroke="currentColor"
|
||||
strokeWidth="0.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
@ -17,7 +17,7 @@ export const SmallSwitchQuestionListGraph = ({
|
||||
width: "77px",
|
||||
height: "51px",
|
||||
position: "fixed",
|
||||
zIndex: "1111",
|
||||
zIndex: "999",
|
||||
right: "0",
|
||||
top: "200px",
|
||||
background: "#333647",
|
||||
|
36
yarn.lock
36
yarn.lock
@ -10557,7 +10557,16 @@ string-natural-compare@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
|
||||
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0:
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^4.1.0, string-width@^4.2.0:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@ -10653,7 +10662,14 @@ stringify-object@^3.3.0:
|
||||
is-obj "^1.0.1"
|
||||
is-regexp "^1.0.0"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
@ -10806,6 +10822,11 @@ svgo@^2.7.0:
|
||||
picocolors "^1.0.0"
|
||||
stable "^0.1.8"
|
||||
|
||||
swiper@^11.1.4:
|
||||
version "11.1.4"
|
||||
resolved "https://registry.yarnpkg.com/swiper/-/swiper-11.1.4.tgz#2f8e303e8bf9e5bc40a3885fc637ae60ff27996c"
|
||||
integrity sha512-1n7kbYJB2dFEpUHRFszq7gys/ofIBrMNibwTiMvPHwneKND/t9kImnHt6CfGPScMHgI+dWMbGTycCKGMoOO1KA==
|
||||
|
||||
swr@^2.2.4:
|
||||
version "2.2.5"
|
||||
resolved "https://registry.yarnpkg.com/swr/-/swr-2.2.5.tgz#063eea0e9939f947227d5ca760cc53696f46446b"
|
||||
@ -11835,7 +11856,7 @@ workbox-window@6.6.1:
|
||||
"@types/trusted-types" "^2.0.2"
|
||||
workbox-core "6.6.1"
|
||||
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
@ -11853,6 +11874,15 @@ wrap-ansi@^6.2.0:
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
dependencies:
|
||||
ansi-styles "^4.0.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
||||
|
Loading…
Reference in New Issue
Block a user