feat: new ResultForm logic

This commit is contained in:
IlyaDoronin 2024-01-10 19:53:37 +03:00
parent 50d2b6cadc
commit 667a0cd069
14 changed files with 221 additions and 107 deletions

@ -17,5 +17,6 @@ export const QUIZ_QUESTION_RESULT: Omit<
price: [0], price: [0],
useImage: true, useImage: true,
usage: true, usage: true,
redirect: "",
}, },
}; };

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

@ -65,12 +65,13 @@ export interface QuizConfig {
| "BlueTheme" | "BlueTheme"
| "BlueDarkTheme"; | "BlueDarkTheme";
resultInfo: { resultInfo: {
when: "before" | "after" | "email"; when: "email" | "";
share: true | false; share: true | false;
replay: true | false; replay: true | false;
theme: string; theme: string;
reply: string; reply: string;
replname: string; replname: string;
showResultForm: "before" | "after";
}; };
startpage: { startpage: {
description: string; description: string;
@ -133,12 +134,13 @@ export const defaultQuizConfig: QuizConfig = {
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: { startpage: {
description: "", description: "",

@ -265,19 +265,21 @@ const SettingField = ({
<GearIcon height="20px" width="20px" color="#7e2aea" /> <GearIcon height="20px" width="20px" color="#7e2aea" />
</IconButton> </IconButton>
</Typography> </Typography>
<IconButton {(type !== "email" || quiz?.config.resultInfo.when !== "email") && (
onClick={() => <IconButton
updateQuiz(quiz?.id, (quiz) => { onClick={() =>
quiz.config.formContact.fields[type].used = false; updateQuiz(quiz?.id, (quiz) => {
}) quiz.config.formContact.fields[type].used = false;
} })
sx={{ }
width: "48px", sx={{
ml: "5px", width: "48px",
}} ml: "5px",
> }}
<Trash /> >
</IconButton> <Trash />
</IconButton>
)}
</Box> </Box>
</> </>
); );

@ -113,7 +113,7 @@ export const ResultSettings = () => {
</Box> </Box>
<WhenCard quizExpand={quizExpand} /> <WhenCard quizExpand={quizExpand} />
{quiz.config.resultInfo.when === "email" && ( {quiz?.config.resultInfo.when === "email" && (
<EmailSettingsCard quizExpand={quizExpand} /> <EmailSettingsCard quizExpand={quizExpand} />
)} )}

@ -1,9 +1,10 @@
import * as React from "react"; import { useState, useEffect } from "react";
import { import {
getQuestionByContentId, getQuestionByContentId,
updateQuestion, updateQuestion,
} from "@root/questions/actions"; } from "@root/questions/actions";
import { useCurrentQuiz } from "@root/quizes/hooks";
import CustomTextField from "@ui_kit/CustomTextField"; import CustomTextField from "@ui_kit/CustomTextField";
@ -26,9 +27,12 @@ import ExpandLessIcon from "@mui/icons-material/ExpandLess";
import Trash from "@icons/trash"; import Trash from "@icons/trash";
import Info from "@icons/Info"; import Info from "@icons/Info";
import SettingIcon from "@icons/questionsPage/settingIcon"; import SettingIcon from "@icons/questionsPage/settingIcon";
import { QuizQuestionResult } from "@model/questionTypes/result";
import { MediaSelectionAndDisplay } from "@ui_kit/MediaSelectionAndDisplay"; import { MediaSelectionAndDisplay } from "@ui_kit/MediaSelectionAndDisplay";
import type { MouseEvent } from "react";
import type { QuizQuestionResult } from "@model/questionTypes/result";
interface Props { interface Props {
resultContract: boolean; resultContract: boolean;
resultData: QuizQuestionResult; resultData: QuizQuestionResult;
@ -57,11 +61,9 @@ export const checkEmptyData = ({
const InfoView = ({ resultData }: { resultData: QuizQuestionResult }) => { const InfoView = ({ resultData }: { resultData: QuizQuestionResult }) => {
const checkEmpty = checkEmptyData({ resultData }); const checkEmpty = checkEmptyData({ resultData });
const question = getQuestionByContentId(resultData.content.rule.parentId); const question = getQuestionByContentId(resultData.content.rule.parentId);
const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>( const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
null,
);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
}; };
@ -126,12 +128,23 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
const isMobile = useMediaQuery(theme.breakpoints.down(790)); const isMobile = useMediaQuery(theme.breakpoints.down(790));
const isTablet = useMediaQuery(theme.breakpoints.down(800)); const isTablet = useMediaQuery(theme.breakpoints.down(800));
const [expand, setExpand] = React.useState(true); const [expand, setExpand] = useState(true);
const [resultCardSettings, setResultCardSettings] = React.useState(false); const [resultCardSettings, setResultCardSettings] = useState(false);
const [buttonPlus, setButtonPlus] = React.useState(true); const [buttonPlus, setButtonPlus] = useState(true);
const question = getQuestionByContentId(resultData.content.rule.parentId); const question = getQuestionByContentId(resultData.content.rule.parentId);
const quiz = useCurrentQuiz();
React.useEffect(() => { useEffect(() => {
if (
resultData.content.hint.text ||
(quiz?.config.resultInfo.showResultForm === "after" &&
resultData.content.redirect)
) {
setButtonPlus(false);
}
}, []);
useEffect(() => {
setExpand(true); setExpand(true);
}, [resultContract]); }, [resultContract]);
@ -390,17 +403,13 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
<Trash /> <Trash />
</IconButton> </IconButton>
</Box> </Box>
<CustomTextField <CustomTextField
value={resultData.content.hint.text} value={resultData.content.hint.text}
onChange={({ target }: { target: HTMLInputElement }) => onChange={({ target }: { target: HTMLInputElement }) =>
updateQuestion( updateQuestion(resultData.id, (question) => {
resultData.id, question.content.hint.text = target.value;
(question) => })
(question.content.hint.text = target.value),
)
} }
fullWidth
maxLength={19} maxLength={19}
placeholder="Например: узнать подробнее" placeholder="Например: узнать подробнее"
sx={{ sx={{
@ -421,6 +430,49 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
}, },
}} }}
/> />
{quiz?.config.resultInfo.showResultForm === "after" && (
<>
<Typography
sx={{
weight: "500",
fontSize: "18px",
margin: "10px 0",
}}
>
Cсылка для кнопки
</Typography>
<CustomTextField
value={resultData.content.redirect}
onChange={({ target }: { target: HTMLInputElement }) =>
updateQuestion<QuizQuestionResult>(
resultData.id,
(question) => {
question.content.redirect = target.value;
},
)
}
placeholder="https://penahub.ru"
sx={{
"& .MuiInputBase-root": {
backgroundColor: "#F2F3F7",
width: isMobile ? undefined : "409px",
height: "48px",
borderRadius: "8px",
},
}}
inputProps={{
sx: {
height: "85px",
borderRadius: "10px",
fontSize: "18px",
lineHeight: "21px",
py: 0,
},
}}
/>
</>
)}
</Box> </Box>
)} )}
</Box> </Box>

@ -22,7 +22,12 @@ import ExpandLessIcon from "@mui/icons-material/ExpandLess";
import ShareNetwork from "@icons/ShareNetwork.svg"; import ShareNetwork from "@icons/ShareNetwork.svg";
import ArrowCounterClockWise from "@icons/ArrowCounterClockWise.svg"; import ArrowCounterClockWise from "@icons/ArrowCounterClockWise.svg";
const whenValues = [ type WhenVariants = {
title: string;
value: "before" | "after";
};
const whenValues: WhenVariants[] = [
{ {
title: "До формы контактов", title: "До формы контактов",
value: "before", value: "before",
@ -31,10 +36,6 @@ const whenValues = [
title: "После формы контактов", title: "После формы контактов",
value: "after", value: "after",
}, },
{
title: "Отправить на E-mail",
value: "email",
},
]; ];
interface Props { interface Props {
@ -170,7 +171,7 @@ export const WhenCard = ({ quizExpand }: Props) => {
</IconButton> </IconButton>
</Box> </Box>
</Box> </Box>
{expand && ( {expand && quiz && (
<> <>
<Box <Box
sx={{ sx={{
@ -189,20 +190,20 @@ export const WhenCard = ({ quizExpand }: Props) => {
{whenValues.map(({ title, value }, index) => ( {whenValues.map(({ title, value }, index) => (
<Box display="flex"> <Box display="flex">
<Button <Button
onClick={() => onClick={() => {
updateQuiz( updateQuiz(quiz.id, (quiz) => {
quiz.id, quiz.config.resultInfo.showResultForm = value;
(quiz) => (quiz.config.resultInfo.when = value), quiz.config;
) });
} }}
key={title} key={title}
sx={{ sx={{
bgcolor: bgcolor:
quiz?.config.resultInfo.when === value quiz?.config.resultInfo.showResultForm === value
? " #7E2AEA" ? " #7E2AEA"
: "#F2F3F7", : "#F2F3F7",
color: color:
quiz?.config.resultInfo.when === value quiz?.config.resultInfo.showResultForm === value
? " white" ? " white"
: "#9A9AAF", : "#9A9AAF",
minWidth: isSmallMonitor minWidth: isSmallMonitor
@ -215,12 +216,12 @@ export const WhenCard = ({ quizExpand }: Props) => {
height: "44px", height: "44px",
fontSize: "17px", fontSize: "17px",
border: border:
quiz?.config.resultInfo.when === value quiz?.config.resultInfo.showResultForm === value
? "none" ? "none"
: "1px solid #9A9AAF", : "1px solid #9A9AAF",
"&:hover": { "&:hover": {
backgroundColor: backgroundColor:
quiz?.config.resultInfo.when === value quiz?.config.resultInfo.showResultForm === value
? "#581CA7" ? "#581CA7"
: "#7E2AEA", : "#7E2AEA",
color: "white", color: "white",
@ -229,9 +230,59 @@ export const WhenCard = ({ quizExpand }: Props) => {
> >
{title} {title}
</Button> </Button>
{value === "email" && <InfoView />}
</Box> </Box>
))} ))}
<Box>
<Button
onClick={() => {
updateQuiz(quiz.id, (quiz) => {
if (quiz.config.resultInfo.when) {
quiz.config.resultInfo.when = "";
return;
}
quiz.config.resultInfo.when = "email";
});
updateQuiz(quiz?.id, (quiz) => {
quiz.config.formContact.fields["email"].used = true;
});
}}
sx={{
bgcolor:
quiz?.config.resultInfo.when === "email"
? " #7E2AEA"
: "#F2F3F7",
color:
quiz?.config.resultInfo.when === "email"
? " white"
: "#9A9AAF",
minWidth: isSmallMonitor
? isMobile
? undefined
: "310px"
: "auto",
borderRadius: "8px",
width: isMobile ? "100%" : "220px",
height: "44px",
fontSize: "17px",
border:
quiz?.config.resultInfo.when === "email"
? "none"
: "1px solid #9A9AAF",
"&:hover": {
backgroundColor:
quiz?.config.resultInfo.when === "email"
? "#581CA7"
: "#7E2AEA",
color: "white",
},
}}
>
Отправить на E-mail
</Button>
<InfoView />
</Box>
</Box> </Box>
{/* { {/* {

@ -186,14 +186,14 @@ export const ContactForm = ({
{ {
// resultQuestion && // resultQuestion &&
// quiz?.config.resultInfo.when === "after" && // quiz?.config.resultInfo.showResultForm === "after" &&
<Button <Button
disabled={!ready} disabled={!ready}
variant="contained" variant="contained"
onClick={() => { onClick={() => {
if ( if (
(quiz?.config.resultInfo.when === "after" || quiz?.config.resultInfo.showResultForm === "after" &&
quiz?.config.resultInfo.when === "email") && resultQuestion?.type === "result" &&
!checkEmptyData({ resultData: resultQuestion }) !checkEmptyData({ resultData: resultQuestion })
) { ) {
setShowContactForm(false); setShowContactForm(false);

@ -22,6 +22,8 @@ import { NameplateLogoFQDark } from "@icons/NameplateLogoFQDark";
import { modes } from "../../utils/themes/Publication/themePublication"; import { modes } from "../../utils/themes/Publication/themePublication";
import { checkEmptyData } from "../ResultPage/cards/ResultCard"; import { checkEmptyData } from "../ResultPage/cards/ResultCard";
import type { QuizQuestionResult } from "@model/questionTypes/result";
type FooterProps = { type FooterProps = {
setCurrentQuestion: (step: AnyTypedQuizQuestion) => void; setCurrentQuestion: (step: AnyTypedQuizQuestion) => void;
question: AnyTypedQuizQuestion; question: AnyTypedQuizQuestion;
@ -108,28 +110,20 @@ export const Footer = ({
} }
}, [question, answers]); }, [question, answers]);
const showResult = (nextQuestion) => { const showResult = (nextQuestion: QuizQuestionResult) => {
console.log("Следующий результат будет вот такой", nextQuestion); console.log("Следующий результат будет вот такой", nextQuestion);
if (nextQuestion && quiz?.config.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 && quiz?.config.resultInfo.when === "before") { if (nextQuestion && quiz?.config.resultInfo.showResultForm === "before") {
if (isEmpty) { if (isEmpty) {
setShowContactForm(true); //до+пустая = кидать на ФК setShowContactForm(true); //до+пустая = кидать на ФК
} else { } else {
setShowResultForm(true); //до+заполнена = показать setShowResultForm(true); //до+заполнена = показать
} }
} }
if ( if (nextQuestion && quiz?.config.resultInfo.showResultForm === "after") {
nextQuestion &&
(quiz?.config.resultInfo.when === "after" ||
quiz?.config.resultInfo.when === "email")
) {
if (isEmpty) { if (isEmpty) {
setShowContactForm(true); //после+пустая setShowContactForm(true); //после+пустая
} else { } else {

@ -105,14 +105,15 @@ export const Question = ({ questions }: QuestionProps) => {
</Box> </Box>
</Box> </Box>
)} )}
{showResultForm && quiz?.config.resultInfo.when === "before" && ( {showResultForm &&
<ResultForm quiz?.config.resultInfo.showResultForm === "before" && (
currentQuestion={currentQuestion} <ResultForm
showContactForm={showContactForm} currentQuestion={currentQuestion}
setShowContactForm={setShowContactForm} showContactForm={showContactForm}
setShowResultForm={setShowResultForm} setShowContactForm={setShowContactForm}
/> setShowResultForm={setShowResultForm}
)} />
)}
{showContactForm && ( {showContactForm && (
<ContactForm <ContactForm
currentQuestion={currentQuestion} currentQuestion={currentQuestion}
@ -121,16 +122,14 @@ export const Question = ({ questions }: QuestionProps) => {
setShowResultForm={setShowResultForm} setShowResultForm={setShowResultForm}
/> />
)} )}
{showResultForm && {showResultForm && quiz?.config.resultInfo.showResultForm === "after" && (
(quiz?.config.resultInfo.when === "after" || <ResultForm
quiz?.config.resultInfo.when === "email") && ( currentQuestion={currentQuestion}
<ResultForm showContactForm={showContactForm}
currentQuestion={currentQuestion} setShowContactForm={setShowContactForm}
showContactForm={showContactForm} setShowResultForm={setShowResultForm}
setShowContactForm={setShowContactForm} />
setShowResultForm={setShowResultForm} )}
/>
)}
{!showContactForm && !showResultForm && ( {!showContactForm && !showResultForm && (
<Footer <Footer
question={currentQuestion} question={currentQuestion}

@ -10,11 +10,13 @@ import { getQuestionByContentId } from "@root/questions/actions";
import { useCurrentQuiz } from "@root/quizes/hooks"; import { useCurrentQuiz } from "@root/quizes/hooks";
import { useQuestionsStore } from "@root/questions/store"; import { useQuestionsStore } from "@root/questions/store";
import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
import YoutubeEmbedIframe from "../../ui_kit/StartPagePreview/YoutubeEmbedIframe.tsx"; import YoutubeEmbedIframe from "../../ui_kit/StartPagePreview/YoutubeEmbedIframe.tsx";
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 { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
import type { QuizQuestionResult } from "../../model/questionTypes/result";
type ResultFormProps = { type ResultFormProps = {
currentQuestion: AnyTypedQuizQuestion; currentQuestion: AnyTypedQuizQuestion;
showContactForm: boolean; showContactForm: boolean;
@ -34,7 +36,7 @@ export const ResultForm = ({
const isMobile = useMediaQuery(theme.breakpoints.down(650)); const isMobile = useMediaQuery(theme.breakpoints.down(650));
const { questions } = useQuestionsStore(); const { questions } = useQuestionsStore();
const searchResult = () => { const searchResult = (): QuizQuestionResult => {
if (Boolean(quiz?.config.haveRoot)) { if (Boolean(quiz?.config.haveRoot)) {
//ищём для ветвления //ищём для ветвления
return (questions.find( return (questions.find(
@ -46,13 +48,13 @@ export const ResultForm = ({
(question) => (question) =>
question.type === "result" && question.type === "result" &&
question.content.rule.parentId === "line", question.content.rule.parentId === "line",
)) as AnyTypedQuizQuestion; )) as QuizQuestionResult;
} else { } else {
return questions.find( return questions.find(
(question) => (question) =>
question.type === "result" && question.type === "result" &&
question.content.rule.parentId === "line", question.content.rule.parentId === "line",
) as AnyTypedQuizQuestion; ) as QuizQuestionResult;
} }
}; };
@ -180,33 +182,41 @@ export const ResultForm = ({
</Box> </Box>
</Box> </Box>
{quiz?.config.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",
}}
>
{quiz?.config.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>
)}
{quiz?.config.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>
); );

@ -45,6 +45,7 @@ export const Page = ({ currentQuestion }: PageProps) => {
}} }}
> >
<img <img
key={currentQuestion.id}
src={currentQuestion.content.back} src={currentQuestion.content.back}
alt="" alt=""
style={{ style={{

@ -121,6 +121,7 @@ export const Variant = ({ currentQuestion }: VariantProps) => {
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={{ style={{
width: "100%", width: "100%",

@ -11,7 +11,7 @@ export const replaceSpacesToEmptyLines = <T = unknown>(object: T): T => {
for (const [key, value] of Object.entries(object)) { for (const [key, value] of Object.entries(object)) {
if (typeof value === "string") { if (typeof value === "string") {
result[key] = value.replace(/\" \"/g, '""'); result[key] = value.replace(" ", "").replace(/\" \"/g, '""');
continue; continue;
} }