frontAnswerer/lib/components/ViewPublicationPage/ContactForm.tsx
nflnkr 06515a64f9 QuizAnswerer component does not fetch data, but receives it as props
WidgetApp and App components fetch quiz data
2024-02-14 14:03:35 +03:00

435 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import AddressIcon from "@icons/ContactFormIcon/AddressIcon";
import EmailIcon from "@icons/ContactFormIcon/EmailIcon";
import NameIcon from "@icons/ContactFormIcon/NameIcon";
import PhoneIcon from "@icons/ContactFormIcon/PhoneIcon";
import TextIcon from "@icons/ContactFormIcon/TextIcon";
import { Box, Button, InputAdornment, Link, TextField as MuiTextField, TextFieldProps, Typography, useTheme } from "@mui/material";
import CustomCheckbox from "@ui_kit/CustomCheckbox";
import { FC, useRef, useState } from "react";
import { sendFC } from "@api/quizRelase";
import { NameplateLogo } from "@icons/NameplateLogo";
import { QuizQuestionResult } from "@model/questionTypes/result";
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
import { quizThemes } from "@utils/themes/Publication/themePublication";
import { enqueueSnackbar } from "notistack";
import { useRootContainerSize } from "../../contexts/RootContainerWidthContext";
import { useQuizData } from "@contexts/QuizDataContext";
const TextField = MuiTextField as unknown as FC<TextFieldProps>; // temporary fix ts(2590)
const EMAIL_REGEXP = /^(([^<>()[\].,:\s@"]+(\.[^<>()[\].,:\s@"]+)*)|(".+"))@(([^<>()[\].,:\s@"]+\.)+[^<>()[\].,:\s@"]{2,})$/iu;
type Props = {
currentQuestion: AnyTypedQuizQuestion;
onShowResult: () => void;
};
export const ContactForm = ({ currentQuestion, onShowResult }: Props) => {
const theme = useTheme();
const { settings, questions, quizId } = useQuizData();
const [ready, setReady] = useState(false);
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [phone, setPhone] = useState("");
const [text, setText] = useState("");
const [adress, setAdress] = useState("");
const fireOnce = useRef(true);
const [fire, setFire] = useState(false);
const isMobile = useRootContainerSize() < 850;
const resultQuestion = currentQuestion.type === "result"
? currentQuestion
: questions.find((question): question is QuizQuestionResult => {
if (settings?.cfg.haveRoot) {
return (
question.type === "result" &&
question.content.rule.parentId === currentQuestion.content.id
);
} else {
return (
question.type === "result" && question.content.rule.parentId === "line"
);
}
});
if (!resultQuestion) throw new Error("Result question not found");
const inputHC = async () => {
const FC = settings.cfg.formContact.fields || settings.cfg.formContact;
const body = {} as any;
if (name.length > 0) body.name = name;
if (email.length > 0) body.email = email;
if (phone.length > 0) body.phone = phone;
if (adress.length > 0) body.address = adress;
if (text.length > 0) body.customs = { [FC.text.text || "Фамилия"]: text };
if (Object.keys(body).length > 0) {
try {
await sendFC({
questionId: currentQuestion.id,
body: body,
qid: quizId,
});
const sessions = JSON.parse(localStorage.getItem("sessions") || "{}");
localStorage.setItem(
"sessions",
JSON.stringify({ ...sessions, [quizId]: new Date().getTime() })
);
} catch (e) {
enqueueSnackbar("ответ не был засчитан");
}
}
};
const FCcopy: any = settings.cfg.formContact.fields || settings.cfg.formContact;
const filteredFC: any = {};
for (const i in FCcopy) {
const field = FCcopy[i];
if (field.used) {
filteredFC[i] = field;
}
}
const isWide = Object.keys(filteredFC).length > 2;
async function handleShowResultsClick() {
//@ts-ignore
const FC: any = settings.cfg.formContact.fields || settings.cfg.formContact;
if (FC["email"].used !== EMAIL_REGEXP.test(email)) {
return enqueueSnackbar("введена некорректная почта");
}
if (fireOnce.current) {
if (
name.length === 0
&& email.length === 0
&& phone.length === 0
&& text.length === 0
&& adress.length === 0
) return enqueueSnackbar("Пожалуйста, заполните поля");
//почта валидна, хоть одно поле заполнено
setFire(true);
try {
await inputHC();
fireOnce.current = false;
const sessions: any = JSON.parse(
localStorage.getItem("sessions") || "{}"
);
sessions[quizId] = Date.now();
localStorage.setItem(
"sessions",
JSON.stringify(sessions)
);
enqueueSnackbar("Данные успешно отправлены");
} catch (e) {
enqueueSnackbar("повторите попытку позже");
}
onShowResult();
}
setFire(false);
}
return (
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: theme.palette.background.default,
height: "100%",
overflow: "auto",
"&::-webkit-scrollbar": {
width: "0",
display: "none",
msOverflowStyle: "none",
},
scrollbarWidth: "none",
msOverflowStyle: "none",
}}
>
<Box
sx={{
width: isWide && !isMobile ? "100%" : isMobile ? undefined : "530px",
borderRadius: "4px",
height: "90vh",
display: isWide && !isMobile ? "flex" : undefined,
}}
>
<Box
sx={{
width: isWide && !isMobile ? "100%" : undefined,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
borderRight: isWide && !isMobile ? "1px solid gray" : undefined,
}}
>
<Typography
sx={{
textAlign: "center",
m: "20px 0",
fontSize: "28px",
color: theme.palette.text.primary,
}}
>
{settings.cfg.formContact.title ||
"Заполните форму, чтобы получить результаты теста"}
</Typography>
{settings.cfg.formContact.desc && (
<Typography
sx={{
color: theme.palette.text.primary,
textAlign: "center",
m: "20px 0",
fontSize: "18px",
}}
>
{settings.cfg.formContact.desc}
</Typography>
)}
</Box>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
backgroundColor: theme.palette.background.default,
p: "30px",
}}
>
<Box
sx={{
display: "flex",
flexDirection: "column",
my: "20px",
}}
>
<Inputs
name={name}
setName={setName}
email={email}
setEmail={setEmail}
phone={phone}
setPhone={setPhone}
text={text}
setText={setText}
adress={adress}
setAdress={setAdress}
/>
</Box>
{
// resultQuestion &&
// settings.cfg.resultInfo.when === "after" &&
<Button
disabled={!(ready && !fire)}
variant="contained"
onClick={handleShowResultsClick}
>
{settings.cfg.formContact?.button || "Получить результаты"}
</Button>
}
<Box
sx={{
display: "flex",
mt: "20px",
width: isMobile ? "300px" : "450px",
}}
>
<CustomCheckbox
label=""
handleChange={({ target }) => {
setReady(target.checked);
}}
checked={ready}
colorIcon={theme.palette.primary.main}
/>
<Typography sx={{ color: theme.palette.text.primary }}>
С&ensp;
<Link href={"https://shub.pena.digital/ppdd"} target="_blank">
Положением об обработке персональных данных{" "}
</Link>
&ensp;и&ensp;
<Link
href={"https://shub.pena.digital/docs/privacy"}
target="_blank"
>
{" "}
Политикой конфиденциальности{" "}
</Link>
&ensp;ознакомлен
</Typography>
</Box>
<Box
component={Link}
target={"_blank"}
href={"https://quiz.pena.digital"}
sx={{
display: "flex",
alignItems: "center",
mt: "20px",
gap: "15px",
textDecoration: "none",
}}
>
<NameplateLogo
style={{
fontSize: "34px",
color: quizThemes[settings.cfg.theme].isLight ? "#151515" : "#FFFFFF",
}}
/>
<Typography
sx={{
fontSize: "20px",
color: quizThemes[settings.cfg.theme].isLight ? "#4D4D4D" : "#F5F7FF",
whiteSpace: "nowrap",
}}
>
Сделано на PenaQuiz
</Typography>
</Box>
</Box>
</Box>
</Box>
);
};
const Inputs = ({
name,
setName,
email,
setEmail,
phone,
setPhone,
text,
setText,
adress,
setAdress,
}: any) => {
const { settings } = useQuizData();
// @ts-ignore
const FC = settings.cfg.formContact.fields || settings.cfg.formContact;
if (!FC) return null;
//@ts-ignore
const Name = (
<CustomInput
//@ts-ignore
onChange={({ target }) => setName(target.value)}
id={name}
title={FC["name"].innerText || "Введите имя"}
desc={FC["name"].text || "имя"}
Icon={NameIcon}
/>
);
//@ts-ignore
const Email = (
<CustomInput
error={!EMAIL_REGEXP.test(email)}
label={!EMAIL_REGEXP.test(email) ? "" : "Некорректная почта"}
//@ts-ignore
onChange={({ target }) => setEmail(target.value)}
id={email}
title={FC["email"].innerText || "Введите Email"}
desc={FC["email"].text || "Email"}
Icon={EmailIcon}
/>
);
const Phone = (
<CustomInput
//@ts-ignore
onChange={({ target }) => setPhone(target.value)}
id={phone}
title={FC["phone"].innerText || "Введите номер телефона"}
desc={FC["phone"].text || "номер телефона"}
Icon={PhoneIcon}
/>
);
//@ts-ignore
const Text = (
<CustomInput
//@ts-ignore
onChange={({ target }) => setText(target.value)}
id={text}
title={FC["text"].text || "Введите фамилию"}
desc={FC["text"].innerText || "фамилию"}
Icon={TextIcon}
/>
);
//@ts-ignore
const Adress = (
<CustomInput
//@ts-ignore
onChange={({ target }) => setAdress(target.value)}
id={adress}
title={FC["address"].innerText || "Введите адрес"}
desc={FC["address"].text || "адрес"}
Icon={AddressIcon}
/>
);
//@ts-ignore
if (Object.values(FC).some((data) => data.used)) {
return (
<>
{FC["name"].used ? Name : <></>}
{FC["email"].used ? Email : <></>}
{FC["phone"].used ? Phone : <></>}
{FC["text"].used ? Text : <></>}
{FC["address"].used ? Adress : <></>}
</>
);
} else {
return (
<>
{Name}
{Email}
{Phone}
</>
);
}
};
const CustomInput = ({ title, desc, Icon, onChange }: any) => {
const theme = useTheme();
const isMobile = useRootContainerSize() < 600;
//@ts-ignore
return (
<Box m="15px 0">
<Typography mb="7px" color={theme.palette.text.primary}>
{title}
</Typography>
<TextField
onChange={onChange}
sx={{
width: isMobile ? "300px" : "350px",
}}
placeholder={desc}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Icon color="gray" />
</InputAdornment>
),
}}
/>
</Box>
);
};