feat: new logic

This commit is contained in:
IlyaDoronin 2024-01-10 21:02:37 +03:00
parent 78204a4b76
commit 42b814cdf9
11 changed files with 297 additions and 252 deletions

@ -17,5 +17,6 @@ export interface QuizQuestionResult extends QuizQuestionBase {
rule: QuestionBranchingRule, rule: QuestionBranchingRule,
hint: QuestionHint; hint: QuestionHint;
autofill: boolean; autofill: boolean;
redirect: string
}; };
} }

@ -6,15 +6,34 @@ import MegaphoneIcon from "@icons/MegaphoneIcon";
import QuestionIcon from "@icons/QuestionIcon"; import QuestionIcon from "@icons/QuestionIcon";
import QuestionsMapIcon from "@icons/QuestionsMapIcon"; import QuestionsMapIcon from "@icons/QuestionsMapIcon";
export const quizSetupSteps = [ export const quizSetupSteps = [
{ stepperText: "Настройка стартовой страницы", sidebarText: "Стартовая страница", sidebarIcon: LayoutIcon }, {
{ stepperText: "Задайте вопросы", sidebarText: "Вопросы", sidebarIcon: QuestionIcon }, stepperText: "Настройка стартовой страницы",
{ stepperText: "Настройте авторезультаты", sidebarText: "Результаты", sidebarIcon: ChartPieIcon }, sidebarText: "Стартовая страница",
// { stepperText: "Оценка графа карты вопросов", sidebarText: "Карта вопросов", sidebarIcon: QuestionsMapIcon }, sidebarIcon: LayoutIcon,
{ stepperText: "Настройте форму контактов", sidebarText: "Форма контактов", sidebarIcon: ContactBookIcon }, },
{ stepperText: "Установите квиз", sidebarText: "Установка квиза", sidebarIcon: FlowArrowIcon }, {
// { stepperText: "Запустите рекламу", sidebarText: "Запуск рекламы", sidebarIcon: MegaphoneIcon }, stepperText: "Задайте вопросы",
sidebarText: "Вопросы",
sidebarIcon: QuestionIcon,
},
{
stepperText: "Настройте авторезультаты",
sidebarText: "Результаты",
sidebarIcon: ChartPieIcon,
},
// { stepperText: "Оценка графа карты вопросов", sidebarText: "Карта вопросов", sidebarIcon: QuestionsMapIcon },
{
stepperText: "Настройте форму контактов",
sidebarText: "Форма контактов",
sidebarIcon: ContactBookIcon,
},
{
stepperText: "Установите квиз",
sidebarText: "Установка квиза",
sidebarIcon: FlowArrowIcon,
},
// { stepperText: "Запустите рекламу", sidebarText: "Запуск рекламы", sidebarIcon: MegaphoneIcon },
] as const; ] as const;
export const maxQuizSetupSteps = quizSetupSteps.length; export const maxQuizSetupSteps = quizSetupSteps.length;
@ -28,143 +47,156 @@ export type QuizType = "quiz" | "form" | null;
export type QuizResultsType = true | null; export type QuizResultsType = true | null;
export interface QuizConfig { export interface QuizConfig {
type: QuizType; type: QuizType;
noStartPage: boolean; noStartPage: boolean;
startpageType: QuizStartpageType; startpageType: QuizStartpageType;
results: QuizResultsType; results: QuizResultsType;
haveRoot: string | null; haveRoot: string | null;
theme: "StandardTheme" | "StandardDarkTheme" | "PinkTheme" | "PinkDarkTheme" | "BlackWhiteTheme" | "OliveTheme" | "YellowTheme" | "GoldDarkTheme" | "PurpleTheme" | "BlueTheme" | "BlueDarkTheme"; theme:
resultInfo: { | "StandardTheme"
when: 'before' | 'after' | 'email', | "StandardDarkTheme"
share: true | false, | "PinkTheme"
replay: true | false, | "PinkDarkTheme"
theme: string, | "BlackWhiteTheme"
reply: string, | "OliveTheme"
replname: string, | "YellowTheme"
} | "GoldDarkTheme"
startpage: { | "PurpleTheme"
description: string; | "BlueTheme"
button: string; | "BlueDarkTheme";
position: QuizStartpageAlignType; resultInfo: {
favIcon: string | null; when: "email" | "";
logo: string | null; share: true | false;
originalLogo: string | null; replay: true | false;
background: { theme: string;
type: null | "image" | "video"; reply: string;
desktop: string | null; replname: string;
originalDesktop: string | null; showResultForm: "before" | "after";
mobile: string | null; };
originalMobile: string | null; startpage: {
video: string | null; description: string;
cycle: boolean; button: string;
}; position: QuizStartpageAlignType;
favIcon: string | null;
logo: string | null;
originalLogo: string | null;
background: {
type: null | "image" | "video";
desktop: string | null;
originalDesktop: string | null;
mobile: string | null;
originalMobile: string | null;
video: string | null;
cycle: boolean;
}; };
formContact: { };
title: string; formContact: {
desc: string; title: string;
name: FCField; desc: string;
email: FCField; name: FCField;
phone: FCField; email: FCField;
text: FCField; phone: FCField;
address: FCField; text: FCField;
button: string address: FCField;
}; button: string;
info: { };
phonenumber: string; info: {
clickable: boolean; phonenumber: string;
orgname: string; clickable: boolean;
site: string; orgname: string;
law?: string; site: string;
}; law?: string;
meta: string; };
meta: string;
} }
type FCField = { type FCField = {
text: string text: string;
innerText: string innerText: string;
key: string key: string;
required: boolean required: boolean;
used: boolean used: boolean;
} };
export const defaultQuizConfig: QuizConfig = { export const defaultQuizConfig: QuizConfig = {
type: null, type: null,
noStartPage: false, noStartPage: false,
startpageType: null, startpageType: null,
results: null, results: null,
haveRoot: null, haveRoot: null,
theme: "StandardTheme", theme: "StandardTheme",
resultInfo: { resultInfo: {
when: 'after', when: "",
share: false, share: false,
replay: false, replay: false,
theme: "", theme: "",
reply: "", reply: "",
replname: "", replname: "",
showResultForm: "after",
},
startpage: {
description: "",
button: "",
position: "left",
favIcon: null,
logo: null,
originalLogo: null,
background: {
type: null,
desktop: null,
originalDesktop: null,
mobile: null,
originalMobile: null,
video: null,
cycle: false,
}, },
startpage: { },
description: "", info: {
button: "", phonenumber: "",
position: "left", clickable: false,
favIcon: null, orgname: "",
logo: null, site: "",
originalLogo: null, law: "",
background: { },
type: null, formContact: {
desktop: null, title: "",
originalDesktop: null, desc: "",
mobile: null, name: {
originalMobile: null, text: "",
video: null, innerText: "",
cycle: false, key: "",
}, required: false,
used: true,
}, },
info: { email: {
phonenumber: "", text: "",
clickable: false, innerText: "",
orgname: "", key: "",
site: "", required: false,
law: "", used: true,
}, },
formContact: { phone: {
title: "", text: "",
desc: "", innerText: "",
name: { key: "",
text: "", required: false,
innerText: "", used: true,
key: "",
required: false,
used: true
},
email: {
text: "",
innerText: "",
key: "",
required: false,
used: true
},
phone: {
text: "",
innerText: "",
key: "",
required: false,
used: true
},
text: {
text: "",
innerText: "",
key: "",
required: false,
used: false
},
address: {
text: "",
innerText: "",
key: "",
required: false,
used: false
},
button: ""
}, },
meta: "", text: {
text: "",
innerText: "",
key: "",
required: false,
used: false,
},
address: {
text: "",
innerText: "",
key: "",
required: false,
used: false,
},
button: "",
},
meta: "",
}; };

@ -9,8 +9,6 @@ export type QuizType = "quiz" | "form";
export type QuizResultsType = true | null; export type QuizResultsType = true | null;
export type QuizResultInfoWhen = 'before' | 'after' | 'email';
export type FCField = { export type FCField = {
text: string text: string
innerText: string innerText: string
@ -61,12 +59,13 @@ export interface QuizConfig {
haveRoot: string; haveRoot: string;
theme: "StandardTheme" | "StandardDarkTheme" | "PinkTheme" | "PinkDarkTheme" | "BlackWhiteTheme" | "OliveTheme" | "YellowTheme" | "GoldDarkTheme" | "PurpleTheme" | "BlueTheme" | "BlueDarkTheme"; theme: "StandardTheme" | "StandardDarkTheme" | "PinkTheme" | "PinkDarkTheme" | "BlackWhiteTheme" | "OliveTheme" | "YellowTheme" | "GoldDarkTheme" | "PurpleTheme" | "BlueTheme" | "BlueDarkTheme";
resultInfo: { resultInfo: {
when: QuizResultInfoWhen; when: "email" | "";
share: boolean; share: boolean;
replay: boolean; replay: boolean;
theme: string; theme: string;
reply: string; reply: string;
replname: string; replname: string;
showResultForm: "before" | "after";
}; };
startpage: { startpage: {
description: string; description: string;

@ -241,7 +241,7 @@ export const ContactForm = ({
enqueueSnackbar("повторите попытку позже") enqueueSnackbar("повторите попытку позже")
} }
if ((settings?.cfg.resultInfo.when === "after" || settings?.cfg.resultInfo.when === "email") && !checkEmptyData({ resultData: resultQuestion })) { if ((settings?.cfg.resultInfo.showResultForm === "after" || settings?.cfg.resultInfo.when === "email") && !checkEmptyData({ resultData: resultQuestion })) {
setShowContactForm(false) setShowContactForm(false)
setShowResultForm(true) setShowResultForm(true)
} }

@ -12,6 +12,8 @@ import { NameplateLogoFQDark } from "@icons/NameplateLogoFQDark";
import { modes } from "../../utils/themes/Publication/themePublication"; import { modes } from "../../utils/themes/Publication/themePublication";
import { checkEmptyData } from "./tools/checkEmptyData"; import { checkEmptyData } from "./tools/checkEmptyData";
import type { QuizQuestionResult } from "@model/questionTypes/result";
type FooterProps = { type FooterProps = {
setCurrentQuestion: (step: AnyTypedQuizQuestion) => void; setCurrentQuestion: (step: AnyTypedQuizQuestion) => void;
question: AnyTypedQuizQuestion; question: AnyTypedQuizQuestion;
@ -85,17 +87,12 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
} }
}, [question, answers]); }, [question, answers]);
const showResult = (nextQuestion: any) => { const showResult = (nextQuestion: QuizQuestionResult) => {
if (nextQuestion && settings?.cfg.resultInfo.when === "email") {
setShowContactForm(true);
return;
}
const isEmpty = checkEmptyData({ resultData: nextQuestion }) const isEmpty = checkEmptyData({ resultData: nextQuestion })
console.log("isEmpty", isEmpty) console.log("isEmpty", isEmpty)
if (nextQuestion) { if (nextQuestion) {
if (nextQuestion && settings?.cfg.resultInfo.when === "before") { if (nextQuestion && settings?.cfg.resultInfo.showResultForm === "before") {
if (isEmpty) { if (isEmpty) {
setShowContactForm(true); //до+пустая = кидать на ФК setShowContactForm(true); //до+пустая = кидать на ФК
@ -104,7 +101,7 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
} }
} }
if (nextQuestion && (settings?.cfg.resultInfo.when === "after" || settings?.cfg.resultInfo.when === "email")) { if (nextQuestion && settings?.cfg.resultInfo.showResultForm === "after") {
if (isEmpty) { if (isEmpty) {
setShowContactForm(true); //после+пустая setShowContactForm(true); //после+пустая

@ -103,7 +103,7 @@ export const Question = ({ questions }: QuestionProps) => {
)} )}
</Box> </Box>
)} )}
{showResultForm && settings?.cfg.resultInfo.when === "before" && ( {showResultForm && settings?.cfg.resultInfo.showResultForm === "before" && (
<ResultForm <ResultForm
currentQuestion={currentQuestion} currentQuestion={currentQuestion}
showContactForm={showContactForm} showContactForm={showContactForm}
@ -119,7 +119,7 @@ export const Question = ({ questions }: QuestionProps) => {
setShowResultForm={setShowResultForm} setShowResultForm={setShowResultForm}
/> />
)} )}
{showResultForm && (settings?.cfg.resultInfo.when === "after" || settings?.cfg.resultInfo.when === "email") && ( {showResultForm && settings?.cfg.resultInfo.showResultForm === "after" && (
<ResultForm <ResultForm
currentQuestion={currentQuestion} currentQuestion={currentQuestion}
showContactForm={showContactForm} showContactForm={showContactForm}

@ -1,12 +1,19 @@
import { Box, Typography, Button, useMediaQuery, useTheme } from "@mui/material"; import {
Box,
Typography,
Button,
useMediaQuery,
useTheme,
} from "@mui/material";
import { useQuestionsStore } from "@root/quizData/store" import { useQuestionsStore } from "@root/quizData/store";
import type { QuizQuestionResult } from "@model/questionTypes/result"; import YoutubeEmbedIframe from "./tools/YoutubeEmbedIframe";
import YoutubeEmbedIframe from "./tools/YoutubeEmbedIframe"
import { NameplateLogo } from "@icons/NameplateLogo"; import { NameplateLogo } from "@icons/NameplateLogo";
import { modes } from "../../utils/themes/Publication/themePublication"; import { modes } from "../../utils/themes/Publication/themePublication";
import type { QuizQuestionResult } from "../../model/questionTypes/result";
type ResultFormProps = { type ResultFormProps = {
currentQuestion: any; currentQuestion: any;
showContactForm: boolean; showContactForm: boolean;
@ -18,32 +25,31 @@ export const ResultForm = ({
showContactForm, showContactForm,
setShowContactForm, setShowContactForm,
setShowResultForm, setShowResultForm,
}: ResultFormProps) => { }: ResultFormProps) => {
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(650)); const isMobile = useMediaQuery(theme.breakpoints.down(650));
const { settings, items } = useQuestionsStore() const { settings, items } = useQuestionsStore();
const mode = modes; const mode = modes;
const searchResult = () => { const searchResult = (): QuizQuestionResult => {
if (Boolean(settings?.cfg.haveRoot)) { if (Boolean(settings?.cfg.haveRoot)) {
//ищём для ветвления //ищём для ветвления
return (items.find( return (items.find(
(question) => (question) =>
question.type === "result" && question.type === "result" &&
question.content.rule.parentId === currentQuestion.content.id, question.content.rule.parentId === currentQuestion.content.id
) || ) ||
items.find( items.find(
(question) => (question) =>
question.type === "result" && question.type === "result" &&
question.content.rule.parentId === "line", question.content.rule.parentId === "line"
)) )) as QuizQuestionResult;
} else { } else {
return items.find( return items.find(
(question) => (question) =>
question.type === "result" && question.type === "result" &&
question.content.rule.parentId === "line", question.content.rule.parentId === "line"
) ) as QuizQuestionResult;
} }
}; };
const resultQuestion = searchResult(); const resultQuestion = searchResult();
@ -52,14 +58,11 @@ export const ResultForm = ({
setShowResultForm(false); setShowResultForm(false);
setShowContactForm(true); setShowContactForm(true);
}; };
console.log(resultQuestion) console.log(resultQuestion);
if (resultQuestion === null || resultQuestion === undefined) { if (resultQuestion === null || resultQuestion === undefined) {
followNextForm();
followNextForm() return <></>;
return <></>
} else { } else {
return ( return (
<Box <Box
sx={{ sx={{
@ -70,7 +73,7 @@ export const ResultForm = ({
height: isMobile ? undefined : "100vh", height: isMobile ? undefined : "100vh",
width: "100vw", width: "100vw",
pt: "28px", pt: "28px",
overflow: "auto" overflow: "auto",
}} }}
> >
<Box <Box
@ -84,16 +87,18 @@ export const ResultForm = ({
> >
{ {
//@ts-ignore //@ts-ignore
!resultQuestion?.content.useImage && resultQuestion.content.video && ( !resultQuestion?.content.useImage &&
<YoutubeEmbedIframe resultQuestion.content.video && (
//@ts-ignore <YoutubeEmbedIframe
videoUrl={resultQuestion.content.video} //@ts-ignore
containerSX={{ videoUrl={resultQuestion.content.video}
width: isMobile ? "100%" : "490px", containerSX={{
height: isMobile ? "100%" : "280px", width: isMobile ? "100%" : "490px",
}} height: isMobile ? "100%" : "280px",
/> }}
)} />
)
}
{ {
//@ts-ignore //@ts-ignore
resultQuestion?.content.useImage && resultQuestion.content.back && ( resultQuestion?.content.useImage && resultQuestion.content.back && (
@ -105,7 +110,8 @@ export const ResultForm = ({
height: isMobile ? "100%" : "280px", height: isMobile ? "100%" : "280px",
}} }}
></Box> ></Box>
)} )
}
{resultQuestion.description !== "" && {resultQuestion.description !== "" &&
resultQuestion.description !== " " && ( resultQuestion.description !== " " && (
<Typography <Typography
@ -132,20 +138,22 @@ export const ResultForm = ({
{ {
//@ts-ignore //@ts-ignore
resultQuestion.content.text !== "" && resultQuestion.content.text !== "" &&
//@ts-ignore //@ts-ignore
resultQuestion.content.text !== " " && ( resultQuestion.content.text !== " " && (
<Typography <Typography
sx={{ sx={{
fontSize: "18px", fontSize: "18px",
m: "20px 0", m: "20px 0",
color: theme.palette.text.primary, color: theme.palette.text.primary,
}} }}
> >
{ {
//@ts-ignore //@ts-ignore
resultQuestion.content.text} resultQuestion.content.text
</Typography> }
)} </Typography>
)
}
</Box> </Box>
<Box width="100%"> <Box width="100%">
@ -165,12 +173,12 @@ export const ResultForm = ({
gap: "10px", gap: "10px",
}} }}
> >
<NameplateLogo <NameplateLogo
style={{ style={{
fontSize: "34px", fontSize: "34px",
color: mode[settings.cfg.theme] ? "#000000" : "#F5F7FF", color: mode[settings.cfg.theme] ? "#000000" : "#F5F7FF",
}} }}
/> />
<Typography <Typography
sx={{ sx={{
fontSize: "20px", fontSize: "20px",
@ -184,36 +192,43 @@ export const ResultForm = ({
</Box> </Box>
</Box> </Box>
{settings?.cfg.resultInfo.when === "before" && ( <Box
<> sx={{
<Box boxShadow: "0 0 15px 0 rgba(0,0,0,.08)",
width: "100%",
flexDirection: "column",
display: "flex",
justifyContent: "center",
alignItems: "center",
p: "20px",
}}
>
{settings?.cfg.resultInfo.showResultForm === "before" && (
<Button
onClick={followNextForm}
variant="contained"
sx={{ sx={{
boxShadow: "0 0 15px 0 rgba(0,0,0,.08)", p: "10px 20px",
width: "100%", width: "210px",
flexDirection: "column", height: "50px",
display: "flex",
justifyContent: "center",
alignItems: "center",
p: "20px",
}} }}
> >
{resultQuestion.content.hint.text || "Узнать подробнее"}
</Button>
)}
{settings?.cfg.resultInfo.showResultForm === "after" &&
resultQuestion.content.redirect && (
<Button <Button
onClick={followNextForm} href={resultQuestion.content.redirect}
variant="contained" variant="contained"
sx={{ sx={{ p: "10px 20px", width: "210px", height: "50px" }}
p: "10px 20px",
width: "210px",
height: "50px",
}}
> >
{resultQuestion.content.hint.text || "Узнать подробнее"} {resultQuestion.content.hint.text || "Перейти на сайт"}
</Button> </Button>
</Box> )}
</> </Box>
)}
</Box> </Box>
</Box> </Box>
); );
} }
}; };

@ -18,7 +18,7 @@ const QID =
process.env.NODE_ENV === "production" ? process.env.NODE_ENV === "production" ?
window.location.pathname.replace(/\//g, '') window.location.pathname.replace(/\//g, '')
: :
"2363ad2c-0c19-4f51-80c0-ed2242daa0c4" "0bed8483-3016-4bca-b8e0-a72c3146f18b"
export const ViewPage = () => { export const ViewPage = () => {

@ -31,6 +31,7 @@ export const Page = ({ currentQuestion }: PageProps) => {
currentQuestion.content.useImage ? ( currentQuestion.content.useImage ? (
<Box sx={{ borderRadius: "12px", border: "1px solid #9A9AAF", overflow: "hidden" }}> <Box sx={{ borderRadius: "12px", border: "1px solid #9A9AAF", overflow: "hidden" }}>
<img <img
key={currentQuestion.id}
src={currentQuestion.content.back} src={currentQuestion.content.back}
alt="" alt=""
style={{ style={{

@ -114,6 +114,7 @@ export const Variant = ({ currentQuestion }: VariantProps) => {
{currentQuestion.content.back && currentQuestion.content.back !== " " && ( {currentQuestion.content.back && currentQuestion.content.back !== " " && (
<Box sx={{ maxWidth: "400px", width: "100%", height: "300px" }}> <Box sx={{ maxWidth: "400px", width: "100%", height: "300px" }}>
<img <img
key={currentQuestion.id}
src={currentQuestion.content.back} src={currentQuestion.content.back}
style={{ width: "100%", height: "100%", objectFit: "cover" }} style={{ width: "100%", height: "100%", objectFit: "cover" }}
alt="" alt=""

@ -1,30 +1,29 @@
export const replaceSpacesToEmptyLines = <T = unknown>(object: T): T => { export const replaceSpacesToEmptyLines = <T = unknown>(object: T): T => {
if (Array.isArray(object)) { if (Array.isArray(object)) {
return object.map(replaceSpacesToEmptyLines) as T; return object.map(replaceSpacesToEmptyLines) as T;
}
if (!object || typeof object !== "object") {
return object;
}
const result: Record<string, unknown> = {};
for (const [key, value] of Object.entries(object)) {
if (typeof value === "string") {
result[key] = value.replace(" ", "").replace(/\" \"/g, '""');
continue;
} }
if (!object || typeof object !== "object") { if (typeof value === "object") {
return object; result[key] = replaceSpacesToEmptyLines(value);
continue;
} }
const result: Record<string, unknown> = {}; result[key] = value;
}
for (const [key, value] of Object.entries(object)) {
if (typeof value === "string") { return result as T;
result[key] = value.replace(/\" \"/g, '""'); };
continue;
}
if (typeof value === "object") {
result[key] = replaceSpacesToEmptyLines(value);
continue;
}
result[key] = value;
}
return result as T;
};