Merge branch 'amo' into dev
This commit is contained in:
commit
3a224b897e
@ -1,5 +1,5 @@
|
||||
import { Button, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import AmoLogo from "../../assets/icons/Amologo.png";
|
||||
import AmoLogo from "@/assets/icons/Amologo.png";
|
||||
import { FC } from "react";
|
||||
|
||||
type AmoButtonProps = {
|
||||
|
||||
@ -3,6 +3,8 @@ import { FC, useMemo } from "react";
|
||||
import CheckboxIcon from "@icons/Checkbox";
|
||||
import { SelectChangeEvent, Typography, useTheme, Box, FormControlLabel, RadioGroup, Radio, useMediaQuery } from "@mui/material";
|
||||
import { MinifiedData, TagKeys } from "@/pages/IntegrationsPage/IntegrationsModal/Amo/types";
|
||||
import { determineScrollBottom } from "@/utils/throttle";
|
||||
import { throttle } from "@frontend/kitui";
|
||||
|
||||
type CustomRadioGroupProps = {
|
||||
items: MinifiedData[] | [];
|
||||
@ -34,17 +36,6 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
|
||||
return item.entity === activeScope;
|
||||
}) : items
|
||||
|
||||
const onScroll = React.useCallback((e: React.UIEvent<HTMLDivElement>) => {
|
||||
const scrollHeight = e.currentTarget.scrollHeight;
|
||||
const scrollTop = e.currentTarget.scrollTop;
|
||||
const clientHeight = e.currentTarget.clientHeight;
|
||||
const scrolledToBottom = scrollTop / (scrollHeight - clientHeight) > 0.9;
|
||||
|
||||
if (scrolledToBottom) {
|
||||
handleScroll();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const formControlLabels =
|
||||
(filteredItems.length !== 0) ?
|
||||
filteredItems.map((item) => (
|
||||
@ -101,12 +92,13 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
|
||||
|
||||
return (
|
||||
<Box
|
||||
onScroll={handleScroll}
|
||||
|
||||
onScroll={(e) => determineScrollBottom(e, throttle(handleScroll, 700))}
|
||||
sx={{
|
||||
border: `1px solid ${theme.palette.grey2.main}`,
|
||||
borderRadius: "12px",
|
||||
padding: "5px",
|
||||
height: "100%",
|
||||
maxHeight: "305px",
|
||||
overflowY: "auto",
|
||||
}}
|
||||
>
|
||||
@ -115,7 +107,6 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
|
||||
name="controlled-radio-buttons-group"
|
||||
value={selectedItemId}
|
||||
onChange={({ target }: SelectChangeEvent<string>) => setSelectedItem(target.value)}
|
||||
onScroll={onScroll}
|
||||
>
|
||||
{formControlLabels}
|
||||
</RadioGroup>
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import * as React from "react";
|
||||
import { FC, useCallback, useMemo, useRef, useState } from "react";
|
||||
import { Avatar, MenuItem, Select, SelectChangeEvent, Typography, useMediaQuery, useTheme, Box } from "@mui/material";
|
||||
import arrow_down from "../../assets/icons/arrow_down.svg";
|
||||
import arrow_down from "@/assets/icons/arrow_down.svg";
|
||||
import { MinifiedData } from "@/pages/IntegrationsPage/IntegrationsModal/Amo/types";
|
||||
import { throttle } from "@frontend/kitui";
|
||||
import { determineScrollBottom } from "@/utils/throttle";
|
||||
|
||||
type CustomSelectProps = {
|
||||
items: MinifiedData[] | [];
|
||||
@ -22,17 +24,6 @@ export const CustomSelect: FC<CustomSelectProps> = ({ items, selectedItemId, set
|
||||
setOpened((isOpened) => !isOpened);
|
||||
}, []);
|
||||
|
||||
const onScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
|
||||
const scrollHeight = e.currentTarget.scrollHeight;
|
||||
const scrollTop = e.currentTarget.scrollTop;
|
||||
const clientHeight = e.currentTarget.clientHeight;
|
||||
const scrolledToBottom = scrollTop / (scrollHeight - clientHeight) > 0.9;
|
||||
|
||||
if (scrolledToBottom) {
|
||||
handleScroll();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const currentItem = useMemo(() => items.find((item) => item.id === selectedItemId) || null, [selectedItemId, items]);
|
||||
|
||||
const menuItems = useMemo(() => {
|
||||
@ -43,7 +34,7 @@ export const CustomSelect: FC<CustomSelectProps> = ({ items, selectedItemId, set
|
||||
value={item.id}
|
||||
sx={{
|
||||
padding: "6px 0",
|
||||
zIndex: 2,
|
||||
zIndex: 3,
|
||||
borderTop: "1px solid rgba(154, 154, 175, 0.1)",
|
||||
width: "auto",
|
||||
}}
|
||||
@ -85,7 +76,7 @@ export const CustomSelect: FC<CustomSelectProps> = ({ items, selectedItemId, set
|
||||
<MenuItem
|
||||
key={"-1"}
|
||||
disabled
|
||||
sx={{ padding: "12px", zIndex: 2 }}
|
||||
sx={{ padding: "12px", zIndex: 3 }}
|
||||
>
|
||||
нет данных
|
||||
</MenuItem>
|
||||
@ -93,10 +84,10 @@ export const CustomSelect: FC<CustomSelectProps> = ({ items, selectedItemId, set
|
||||
}, [items, selectedItemId]);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box mt={"20px"}>
|
||||
<Box
|
||||
sx={{
|
||||
zIndex: 3,
|
||||
zIndex: 4,
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
height: "56px",
|
||||
@ -149,9 +140,9 @@ export const CustomSelect: FC<CustomSelectProps> = ({ items, selectedItemId, set
|
||||
MenuProps={{
|
||||
disablePortal: true,
|
||||
PaperProps: {
|
||||
onScroll: onScroll,
|
||||
onScroll: (e) => determineScrollBottom(e, throttle(handleScroll, 700)),
|
||||
style: {
|
||||
zIndex: 2,
|
||||
zIndex: 3,
|
||||
maxHeight: "300px",
|
||||
overflow: "auto",
|
||||
overflowX: "auto",
|
||||
@ -173,7 +164,7 @@ export const CustomSelect: FC<CustomSelectProps> = ({ items, selectedItemId, set
|
||||
border: 0,
|
||||
},
|
||||
"& .MuiMenu-root.MuiModal-root": {
|
||||
zIndex: 0,
|
||||
zIndex: 2,
|
||||
},
|
||||
}}
|
||||
onChange={({ target }: SelectChangeEvent<string>) => setSelectedItem(target.value)}
|
||||
|
||||
184
src/pages/IntegrationsPage/IntegrationsModal/Amo/AccountInfo.tsx
Normal file
184
src/pages/IntegrationsPage/IntegrationsModal/Amo/AccountInfo.tsx
Normal file
@ -0,0 +1,184 @@
|
||||
import { Box, Button, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { StepButtonsBlock } from "./StepButtonsBlock";
|
||||
import { FC } from "react";
|
||||
import { AccountResponse } from "@api/integration";
|
||||
import AccountSetting from "@icons/AccountSetting";
|
||||
|
||||
type AmoAccountInfoProps = {
|
||||
handleNextStep: () => void;
|
||||
accountInfo: AccountResponse | null;
|
||||
toChangeAccount: () => void;
|
||||
};
|
||||
|
||||
export const AccountInfo: FC<AmoAccountInfoProps> = ({ handleNextStep, accountInfo, toChangeAccount }) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
|
||||
const infoItem = (title: string, value: string | number | undefined) => (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
mt: "20px",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ width: isMobile ? "100%" : "45%" }}>
|
||||
<Typography sx={{
|
||||
fontSize: "16px",
|
||||
lineHeight: "18.96px",
|
||||
|
||||
color: theme.palette.grey2.main
|
||||
}}>{title}:</Typography>
|
||||
</Box>
|
||||
<Box sx={{
|
||||
width: isMobile ? "100%" : "45%",
|
||||
mt: "5px",
|
||||
}}>
|
||||
<Typography>{value || "нет данных"}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const infoItemLink = (title: string, link: string | undefined) => (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
mt: "20px",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<Typography sx={{
|
||||
color: theme.palette.grey2.main,
|
||||
fontSize: "16px",
|
||||
lineHeight: "18.96px",
|
||||
}}>{title}:</Typography>
|
||||
</Box>
|
||||
<Box sx={{ width: "100%" }}>
|
||||
{
|
||||
link ?
|
||||
<a
|
||||
target="_blank"
|
||||
href={link}
|
||||
style={{
|
||||
wordBreak: "break-word",
|
||||
fontSize: "18px",
|
||||
lineHeight: "21.33px",
|
||||
color: "#7E2AEA"
|
||||
}}
|
||||
>
|
||||
{link}
|
||||
</a>
|
||||
:
|
||||
<Typography>не указана</Typography>
|
||||
}
|
||||
</Box>
|
||||
</Box >
|
||||
);
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "inline-flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-between",
|
||||
height: "100%",
|
||||
overflow: "auto",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
|
||||
flexDirection: isMobile ? "column" : "row",
|
||||
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "auto",
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
color: theme.palette.grey3.main,
|
||||
lineHeight: "21.33px",
|
||||
}}
|
||||
>
|
||||
Информация об аккаунте
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
m: "5px 0 19px 0",
|
||||
lineHeight: "16.59px",
|
||||
color: theme.palette.grey2.main,
|
||||
fontSize: "14px",
|
||||
}}
|
||||
>
|
||||
1 шаг
|
||||
</Typography>
|
||||
{infoItem("Amo ID", accountInfo?.amoID)}
|
||||
{infoItem("Имя аккаунта", accountInfo?.name)}
|
||||
{infoItemLink("ЛК в amo", `https://${accountInfo?.subdomain}.amocrm.ru/dashboard/`)}
|
||||
{infoItemLink("Профиль пользователя в amo", `https://${accountInfo?.subdomain}.amocrm.ru/settings/users/`)}
|
||||
{infoItem("Страна пользователя", accountInfo?.country)}
|
||||
</Box>
|
||||
<Box>
|
||||
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={
|
||||
<AccountSetting
|
||||
color={theme.palette.brightPurple.main}
|
||||
height={"20px"}
|
||||
width={"20px"}
|
||||
/>
|
||||
}
|
||||
onClick={toChangeAccount}
|
||||
sx={{
|
||||
height: "44px",
|
||||
padding: "0",
|
||||
mt: isMobile ? "30px" : "0",
|
||||
width: "205px",
|
||||
backgroundColor: "transparent",
|
||||
color: theme.palette.brightPurple.main,
|
||||
"& .MuiButton-startIcon": {
|
||||
marginRight: isMobile ? 0 : "8px",
|
||||
marginLeft: 0,
|
||||
},
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.brightPurple.main,
|
||||
color: theme.palette.common.white,
|
||||
"& path": {
|
||||
stroke: theme.palette.common.white,
|
||||
},
|
||||
"& circle": {
|
||||
stroke: theme.palette.common.white,
|
||||
},
|
||||
},
|
||||
"&:active": {
|
||||
backgroundColor: "#581CA7",
|
||||
color: theme.palette.common.white,
|
||||
"& path": {
|
||||
stroke: theme.palette.common.white,
|
||||
},
|
||||
"& circle": {
|
||||
stroke: theme.palette.common.white,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
Сменить аккаунт
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
<StepButtonsBlock
|
||||
isSmallBtnDisabled={true}
|
||||
onLargeBtnClick={handleNextStep}
|
||||
largeBtnText={"Далее"}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@ -1,87 +0,0 @@
|
||||
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock";
|
||||
import { FC } from "react";
|
||||
import { AccountResponse } from "@api/integration";
|
||||
|
||||
type AmoAccountInfoProps = {
|
||||
handleNextStep: () => void;
|
||||
accountInfo: AccountResponse;
|
||||
};
|
||||
|
||||
export const AmoAccountInfo: FC<AmoAccountInfoProps> = ({ handleNextStep, accountInfo }) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
|
||||
const infoItem = (title: string, value: string | number) => (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: isMobile ? "column" : "row",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ width: isMobile ? "100%" : "45%" }}>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>{title}:</Typography>
|
||||
</Box>
|
||||
<Box sx={{ width: isMobile ? "100%" : "45%" }}>
|
||||
<Typography>{value || "нет данных"}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const infoItemLink = (title: string, link: string) => (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: isMobile ? "column" : "row",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ width: isMobile ? "100%" : "45%" }}>
|
||||
<Typography sx={{ color: theme.palette.grey2.main }}>{title}:</Typography>
|
||||
</Box>
|
||||
<Box sx={{ width: isMobile ? "100%" : "45%" }}>
|
||||
<a
|
||||
target="_blank"
|
||||
href={link}
|
||||
style={{wordBreak: "break-word"}}
|
||||
>
|
||||
{link}
|
||||
</a>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
height: "100%",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: isMobile ? "20px" : "60px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: isMobile ? "10px" : "20px",
|
||||
}}
|
||||
>
|
||||
{infoItem("Amo ID", accountInfo.amoID)}
|
||||
{infoItem("Имя аккаунта", accountInfo.name)}
|
||||
{/* {infoItem("Email аккаунта", accountInfo.email)} */}
|
||||
{infoItemLink("ЛК в amo", `https://${accountInfo.subdomain}.amocrm.ru/dashboard/`)}
|
||||
{infoItemLink("Профиль пользователя в amo", `https://${accountInfo.subdomain}.amocrm.ru/settings/users/`)}
|
||||
{infoItem("Страна пользователя", accountInfo.country)}
|
||||
</Box>
|
||||
<StepButtonsBlock
|
||||
isSmallBtnDisabled={true}
|
||||
onLargeBtnClick={handleNextStep}
|
||||
largeBtnText={"Далее"}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@ -1,461 +0,0 @@
|
||||
import React, { FC, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Dialog, IconButton, Typography, useMediaQuery, useTheme, Box, Skeleton } from "@mui/material";
|
||||
import { useQuestions } from "@/stores/questions/hooks";
|
||||
import { redirect } from "react-router-dom";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
|
||||
import { AmoRemoveAccount } from "./AmoRemoveAccount/AmoRemoveAccount";
|
||||
import { AmoDeleteTagQuestion } from "./AmoRemoveAccount/AmoDeleteTagQuestion";
|
||||
import { AmoLogin } from "./AmoLogin/AmoLogin";
|
||||
import { Pipelines } from "./Pipelines/Pipelines";
|
||||
import { PipelineSteps } from "./PipelineSteps/PipelineSteps";
|
||||
import { DealPerformers } from "./DealPerformers/DealPerformers";
|
||||
import { AmoTags } from "./AmoTags/AmoTags";
|
||||
import { AmoQuestions } from "./AmoQuestions/AmoQuestions";
|
||||
import { AmoModalTitle } from "./AmoModalTitle/AmoModalTitle";
|
||||
import { AmoSettingsBlock } from "./SettingsBlock/AmoSettingsBlock";
|
||||
import { AmoAccountInfo } from "./AmoAccountInfo/AmoAccountInfo";
|
||||
import { useAmoIntegration } from "./useAmoIntegration";
|
||||
import { MinifiedData, QuestionKeys, TagKeys, TagQuestionHC } from "./types";
|
||||
import { Quiz } from "@/model/quiz/quiz";
|
||||
import { setIntegrationRules, updateIntegrationRules } from "@/api/integration";
|
||||
|
||||
type IntegrationsModalProps = {
|
||||
isModalOpen: boolean;
|
||||
handleCloseModal: () => void;
|
||||
companyName: string | null;
|
||||
quiz: Quiz;
|
||||
};
|
||||
|
||||
const FCTranslate = {
|
||||
"name": "имя",
|
||||
"email": "почта",
|
||||
"phone": "телефон",
|
||||
"text": "номер",
|
||||
"address": "адрес",
|
||||
}
|
||||
|
||||
export const AmoCRMModal: FC<IntegrationsModalProps> = ({ isModalOpen, handleCloseModal, companyName, quiz }) => {
|
||||
//Если нет контекста квиза, то и делать на этой страничке нечего
|
||||
if (quiz?.backendId === undefined) {
|
||||
redirect("/list");
|
||||
return null;
|
||||
}
|
||||
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||
|
||||
const { questions } = useQuestions();
|
||||
const minifiedQuestions = useMemo(
|
||||
() =>
|
||||
questions
|
||||
.filter((q) => q.type !== "result" && q.type !== null)
|
||||
.map(({ backendId, title }) => ({
|
||||
id: backendId.toString() as string,
|
||||
title,
|
||||
})),
|
||||
[questions]
|
||||
);
|
||||
const FieldsAllowedFC = useMemo(
|
||||
() => {
|
||||
const list: MinifiedData[] = []
|
||||
if (quiz.config.showfc) {
|
||||
const fields = quiz.config.formContact.fields
|
||||
for (let key in fields) {
|
||||
if (fields[key].used) list.push({
|
||||
id: key,
|
||||
title: FCTranslate[key],
|
||||
entity: "Contact",
|
||||
})
|
||||
}
|
||||
}
|
||||
return list;
|
||||
},
|
||||
[quiz]
|
||||
);
|
||||
|
||||
const [step, setStep] = useState<number>(0);
|
||||
const [isSettingsBlock, setIsSettingsBlock] = useState<boolean>(false);
|
||||
const [isTryRemoveAccount, setIsTryRemoveAccount] = useState<boolean>(false);
|
||||
const [openDelete, setOpenDelete] = useState<TagQuestionHC | null>(null);
|
||||
|
||||
|
||||
const {
|
||||
isLoadingPage,
|
||||
firstRules,
|
||||
accountInfo,
|
||||
arrayOfPipelines,
|
||||
arrayOfPipelinesSteps,
|
||||
arrayOfUsers,
|
||||
arrayOfTags,
|
||||
arrayOfFields,
|
||||
selectedPipeline,
|
||||
setSelectedPipeline,
|
||||
selectedCurrentFields,
|
||||
selectedPipelineStep,
|
||||
setSelectedPipelineStep,
|
||||
selectedDealUser,
|
||||
setSelectedDealPerformer,
|
||||
questionsBackend,
|
||||
selectedTags,
|
||||
setSelectedTags,
|
||||
selectedQuestions,
|
||||
setSelectedQuestions,
|
||||
setPageOfPipelines,
|
||||
setPageOfPipelinesSteps,
|
||||
setPageOfUsers,
|
||||
setPageOfTags,
|
||||
setSelectedCurrentFields,
|
||||
} = useAmoIntegration({
|
||||
quizID: quiz.backendId,
|
||||
isModalOpen,
|
||||
isTryRemoveAccount,
|
||||
questions,
|
||||
});
|
||||
|
||||
|
||||
const handleAddTagQuestion = useCallback(
|
||||
(scope: QuestionKeys | TagKeys, id: string, type: "question" | "tag") => {
|
||||
if (!scope || !id) return;
|
||||
|
||||
if (type === "tag") {
|
||||
setSelectedTags((prevState) => ({
|
||||
...prevState,
|
||||
[scope]: [...prevState[scope as TagKeys], id],
|
||||
}));
|
||||
}
|
||||
|
||||
if (type === "question") {
|
||||
const q = questions.find(e => e.backendId === Number(id))
|
||||
setSelectedQuestions((prevState) => ({
|
||||
...prevState,
|
||||
[scope]: [...prevState[scope as QuestionKeys], {
|
||||
id,
|
||||
title: q?.title || "вопрос",
|
||||
entity: scope,
|
||||
}],
|
||||
}));
|
||||
}
|
||||
},
|
||||
[setSelectedQuestions, setSelectedTags, questions]
|
||||
);
|
||||
const handleDeleteTagQuestion = useCallback(() => {
|
||||
if (openDelete === null || !openDelete.scope || !openDelete.id || !openDelete.type) return;
|
||||
if (openDelete.type === "tag") {
|
||||
let newArray = selectedTags[openDelete.scope];
|
||||
const index = newArray.indexOf(openDelete.id);
|
||||
if (index !== -1) newArray.splice(index, 1);
|
||||
|
||||
setSelectedTags((prevState) => ({
|
||||
...prevState,
|
||||
[openDelete.scope]: newArray,
|
||||
}));
|
||||
}
|
||||
|
||||
if (openDelete.type === "question") {
|
||||
let newArray = selectedQuestions
|
||||
newArray[openDelete.scope as QuestionKeys] = newArray[openDelete.scope as QuestionKeys].filter(e => e.id !== openDelete.id)
|
||||
// let index = -1
|
||||
// selectedQuestions[openDelete.scope].forEach((e, i) => {
|
||||
// if (e.subTitle === openDelete.id) index = i
|
||||
// })
|
||||
// if (index !== -1) newArray.splice(index, 1);
|
||||
// setSelectedQuestions((prevState) => ({
|
||||
// ...prevState,
|
||||
// [openDelete.scope]: newArray,
|
||||
// }));
|
||||
setSelectedQuestions(newArray);
|
||||
setSelectedCurrentFields(selectedCurrentFields.filter(e => e.id !== openDelete.id));
|
||||
|
||||
}
|
||||
setOpenDelete(null);
|
||||
}, [openDelete]);
|
||||
|
||||
const handleNextStep = () => {
|
||||
setStep((prevState) => prevState + 1);
|
||||
};
|
||||
const handlePrevStep = () => {
|
||||
setStep((prevState) => prevState - 1);
|
||||
};
|
||||
const handleSave = () => {
|
||||
if (quiz?.backendId === undefined) return;
|
||||
if (selectedPipeline === null) return enqueueSnackbar("Выберите воронку");
|
||||
if (selectedPipeline === null) return enqueueSnackbar("Выберите этап воронки");
|
||||
|
||||
const body = {
|
||||
PipelineID: Number(selectedPipeline),
|
||||
StepID: Number(selectedPipelineStep),
|
||||
PerformerID: Number(selectedDealUser),
|
||||
// FieldsRule: questionsBackend,
|
||||
TagsToAdd: selectedTags,
|
||||
};
|
||||
|
||||
const FieldsRule = {
|
||||
Company: { QuestionID: {} },
|
||||
Lead: { QuestionID: {} },
|
||||
Customer: { QuestionID: {} },
|
||||
Contact: {
|
||||
QuestionID: {},
|
||||
ContactRuleMap: {
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
for (let key in FieldsRule) {
|
||||
selectedQuestions[key as QuestionKeys].forEach((data) => {
|
||||
FieldsRule[key as QuestionKeys].QuestionID[data.id] = 0;
|
||||
});
|
||||
}
|
||||
|
||||
selectedCurrentFields.forEach((data) => {
|
||||
if (data.entity === "Contact") {
|
||||
FieldsRule.Contact.ContactRuleMap[data.id] = Number(data.amoId)
|
||||
} else {
|
||||
FieldsRule[data.entity].QuestionID[data.id] = Number(data.amoId) || 0
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
for (let key in body.TagsToAdd) {
|
||||
body.TagsToAdd[key as TagKeys] = body.TagsToAdd[key as TagKeys].map((id) => Number(id));
|
||||
}
|
||||
body.FieldsRule = FieldsRule;
|
||||
|
||||
if (firstRules) {
|
||||
setIntegrationRules(quiz.backendId.toString(), body);
|
||||
} else {
|
||||
updateIntegrationRules(quiz.backendId.toString(), body);
|
||||
}
|
||||
|
||||
handleCloseModal();
|
||||
setStep(1);
|
||||
};
|
||||
const steps = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: accountInfo ? "Информация об аккаунте" : "Авторизация в аккаунте",
|
||||
isSettingsAvailable: false,
|
||||
component: accountInfo ? (
|
||||
<AmoAccountInfo
|
||||
handleNextStep={handleNextStep}
|
||||
accountInfo={accountInfo}
|
||||
/>
|
||||
) : (
|
||||
<AmoLogin handleNextStep={handleNextStep} />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Выбор воронки",
|
||||
isSettingsAvailable: true,
|
||||
component: (
|
||||
<Pipelines
|
||||
users={arrayOfUsers}
|
||||
pipelines={arrayOfPipelines}
|
||||
handlePrevStep={handlePrevStep}
|
||||
handleNextStep={handleNextStep}
|
||||
selectedDealUser={selectedDealUser}
|
||||
setSelectedDealPerformer={setSelectedDealPerformer}
|
||||
selectedPipeline={selectedPipeline}
|
||||
setSelectedPipeline={setSelectedPipeline}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Выбор этапа воронки",
|
||||
isSettingsAvailable: true,
|
||||
component: (
|
||||
<PipelineSteps
|
||||
users={arrayOfUsers}
|
||||
selectedDealUser={selectedDealUser}
|
||||
selectedStep={selectedPipelineStep}
|
||||
steps={arrayOfPipelinesSteps}
|
||||
setSelectedDealPerformer={setSelectedDealPerformer}
|
||||
setSelectedStep={setSelectedPipelineStep}
|
||||
handlePrevStep={handlePrevStep}
|
||||
handleNextStep={handleNextStep}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Сделка",
|
||||
isSettingsAvailable: true,
|
||||
component: (
|
||||
<DealPerformers
|
||||
handlePrevStep={handlePrevStep}
|
||||
handleNextStep={handleNextStep}
|
||||
users={arrayOfUsers}
|
||||
selectedDealUser={selectedDealUser}
|
||||
setSelectedDealPerformer={setSelectedDealPerformer}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Добавление тегов",
|
||||
isSettingsAvailable: true,
|
||||
component: (
|
||||
<AmoTags
|
||||
tagsItems={arrayOfTags}
|
||||
selectedTags={selectedTags}
|
||||
openDelete={setOpenDelete}
|
||||
handleScroll={() => { }}
|
||||
handleAddTag={handleAddTagQuestion}
|
||||
handlePrevStep={handlePrevStep}
|
||||
handleNextStep={handleNextStep}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Соотнесение вопросов и сущностей",
|
||||
isSettingsAvailable: true,
|
||||
component: (
|
||||
<AmoQuestions
|
||||
setSelectedCurrentFields={setSelectedCurrentFields}
|
||||
fieldsItems={arrayOfFields}
|
||||
selectedCurrentFields={selectedCurrentFields}
|
||||
questionsItems={minifiedQuestions}
|
||||
selectedQuestions={selectedQuestions}
|
||||
openDelete={setOpenDelete}
|
||||
handleAddQuestion={handleAddTagQuestion}
|
||||
handlePrevStep={handlePrevStep}
|
||||
handleNextStep={handleSave}
|
||||
FieldsAllowedFC={FieldsAllowedFC}
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
arrayOfPipelines,
|
||||
arrayOfPipelinesSteps,
|
||||
arrayOfUsers,
|
||||
arrayOfTags,
|
||||
arrayOfFields,
|
||||
selectedPipeline,
|
||||
selectedPipelineStep,
|
||||
selectedDealUser,
|
||||
selectedQuestions,
|
||||
selectedTags,
|
||||
arrayOfPipelines,
|
||||
arrayOfPipelinesSteps,
|
||||
arrayOfUsers,
|
||||
minifiedQuestions,
|
||||
selectedCurrentFields,
|
||||
]
|
||||
);
|
||||
|
||||
const stepTitles = steps.map((step) => step.title);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isModalOpen}
|
||||
onClose={handleCloseModal}
|
||||
fullWidth
|
||||
// fullScreen={isMobile}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
maxWidth: isTablet ? "100%" : "920px",
|
||||
maxHeight: isTablet ? "100%" : "660px",
|
||||
borderRadius: "12px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "68px",
|
||||
backgroundColor: theme.palette.background.default,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: isMobile ? "20px" : "24px",
|
||||
fontWeight: "500",
|
||||
padding: "20px",
|
||||
color: theme.palette.grey2.main,
|
||||
}}
|
||||
>
|
||||
Интеграция с {companyName ? companyName : "партнером"}
|
||||
</Typography>
|
||||
</Box>
|
||||
<IconButton
|
||||
onClick={handleCloseModal}
|
||||
sx={{
|
||||
width: "12px",
|
||||
height: "12px",
|
||||
position: "absolute",
|
||||
right: "15px",
|
||||
top: "15px",
|
||||
}}
|
||||
>
|
||||
<CloseIcon sx={{ width: "12px", height: "12px", transform: "scale(1.5)" }} />
|
||||
</IconButton>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: isTablet ? "100%" : "920px",
|
||||
height: "600px",
|
||||
padding: "15px 20px 15px",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
{isLoadingPage ?
|
||||
<Skeleton
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
transform: "none",
|
||||
}}
|
||||
/> :
|
||||
<>
|
||||
<AmoModalTitle
|
||||
step={step}
|
||||
steps={steps}
|
||||
isSettingsBlock={isSettingsBlock}
|
||||
setIsSettingsBlock={setIsSettingsBlock}
|
||||
setStep={setStep}
|
||||
startRemoveAccount={() => setIsTryRemoveAccount(true)}
|
||||
/>
|
||||
{openDelete !== null ? (
|
||||
<AmoDeleteTagQuestion
|
||||
close={() => setOpenDelete(null)}
|
||||
deleteItem={handleDeleteTagQuestion}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{isTryRemoveAccount && <AmoRemoveAccount handleCloseModal={handleCloseModal} stopThisPage={() => setIsTryRemoveAccount(false)} />}
|
||||
{isSettingsBlock && (
|
||||
<Box sx={{ flexGrow: 1, width: "100%" }}>
|
||||
<AmoSettingsBlock
|
||||
stepTitles={stepTitles}
|
||||
setIsSettingsBlock={setIsSettingsBlock}
|
||||
setStep={setStep}
|
||||
selectedDealUser={arrayOfUsers.find((u) => u.id === selectedDealUser)?.title || "не указан"}
|
||||
selectedFunnel={arrayOfPipelines.find((p) => p.id === selectedPipeline)?.title || "нет данных"}
|
||||
selectedStage={
|
||||
arrayOfPipelinesSteps.find((s) => s.id === selectedPipelineStep)?.title || "нет данных"
|
||||
}
|
||||
selectedQuestions={selectedQuestions}
|
||||
selectedTags={selectedTags}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
{!isSettingsBlock && !isTryRemoveAccount && (
|
||||
<Box sx={{ flexGrow: 1, width: "100%" }}>{steps[step].component}</Box>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
|
||||
|
||||
</Box>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export const diffArr = (arr_A: MinifiedData[], arr_B: MinifiedData[]) => {
|
||||
return arr_A.filter(person_A => !arr_B.some(person_B => person_A.id === person_B.id));
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { FC } from "react";
|
||||
import { AmoButton } from "../../../../../components/AmoButton/AmoButton";
|
||||
import { AmoButton } from "../../../../components/AmoButton/AmoButton";
|
||||
import { connectAmo } from "@api/integration";
|
||||
|
||||
type IntegrationStep1Props = {
|
||||
@ -1,97 +0,0 @@
|
||||
import { FC, useState } from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { ItemsSelectionView } from "../AmoQuestions/ItemsSelectionView/ItemsSelectionView";
|
||||
import { TagsDetailsView } from "./TagsDetailsView/TagsDetailsView";
|
||||
import { MinifiedData, QuestionKeys, SelectedTags, TagKeys, TagQuestionHC } from "../types";
|
||||
import { DataConstrictor } from "../Components/DataConstrictor";
|
||||
|
||||
type Props = {
|
||||
tagsItems: MinifiedData[] | [];
|
||||
selectedTags: SelectedTags;
|
||||
handleAddTag: (scope: QuestionKeys | TagKeys, id: string, type: "question" | "tag") => void;
|
||||
openDelete: (data: TagQuestionHC) => void;
|
||||
handleScroll: () => void;
|
||||
handlePrevStep: () => void;
|
||||
handleNextStep: () => void;
|
||||
};
|
||||
|
||||
export const AmoTags: FC<Props> = ({
|
||||
tagsItems,
|
||||
selectedTags,
|
||||
handleAddTag,
|
||||
openDelete,
|
||||
handleScroll,
|
||||
handlePrevStep,
|
||||
handleNextStep,
|
||||
}) => {
|
||||
const [sortedTagsItems, setSortedTagsItems] = useState<MinifiedData[] | []>(tagsItems);
|
||||
|
||||
const [isSelection, setIsSelection] = useState<boolean>(false);
|
||||
const [activeScope, setActiveScope] = useState<TagKeys | null>(null);
|
||||
const [selectedTag, setSelectedTag] = useState<string | null>(null);
|
||||
|
||||
const handleAdd = () => {
|
||||
if (activeScope === null || selectedTag === null) return;
|
||||
setActiveScope(null);
|
||||
handleAddTag(activeScope, selectedTag, "tag");
|
||||
};
|
||||
const handleDelete = (id: string, scope: TagKeys) => {
|
||||
openDelete({
|
||||
id,
|
||||
scope,
|
||||
type: "tag",
|
||||
});
|
||||
};
|
||||
const startConstrictor = (substr: string) => {
|
||||
const a = tagsItems.filter((mData) => mData.title.toLowerCase().startsWith(substr.toLowerCase()))
|
||||
setSortedTagsItems(a);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
{isSelection && activeScope !== null ? (
|
||||
// Здесь выбираем элемент в табличку
|
||||
<>
|
||||
<DataConstrictor
|
||||
isError={sortedTagsItems.length === 0}
|
||||
constrictor={startConstrictor}
|
||||
/>
|
||||
<ItemsSelectionView
|
||||
items={sortedTagsItems}
|
||||
selectedItemId={selectedTag}
|
||||
setSelectedItem={setSelectedTag}
|
||||
handleScroll={handleScroll}
|
||||
activeScope={activeScope}
|
||||
onSmallBtnClick={() => {
|
||||
setActiveScope(null);
|
||||
setIsSelection(false);
|
||||
}}
|
||||
onLargeBtnClick={() => {
|
||||
handleAdd();
|
||||
setActiveScope(null);
|
||||
setIsSelection(false);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
// Табличка
|
||||
<TagsDetailsView
|
||||
items={tagsItems}
|
||||
setActiveScope={setActiveScope}
|
||||
selectedTags={selectedTags}
|
||||
setIsSelection={setIsSelection}
|
||||
handleNextStep={handleNextStep}
|
||||
handlePrevStep={handlePrevStep}
|
||||
deleteHC={handleDelete}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,71 @@
|
||||
import { Box, IconButton, Typography, useTheme } from "@mui/material";
|
||||
import { FC } from "react";
|
||||
import Trash from "@icons/trash";
|
||||
|
||||
type AnswerItemProps = {
|
||||
fieldName: string;
|
||||
fieldValue: string;
|
||||
deleteHC: () => void;
|
||||
};
|
||||
|
||||
export const AnswerItem: FC<AnswerItemProps> = ({ fieldName, fieldValue, deleteHC }) => {
|
||||
console.log("AnswerItem")
|
||||
console.log(fieldName)
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
padding: "10px 20px",
|
||||
height: "140px",
|
||||
borderBottom: `1px solid ${theme.palette.background.default}`,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
overflow: "hidden",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
fontWeight: 500,
|
||||
color: theme.palette.grey3.main,
|
||||
textOverflow: "ellipsis",
|
||||
overflow: "hidden",
|
||||
width: "100%",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
{fieldName}
|
||||
</Typography>
|
||||
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
fontWeight: 400,
|
||||
color: theme.palette.grey3.main,
|
||||
textOverflow: "ellipsis",
|
||||
overflow: "hidden",
|
||||
width: "100%",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
{fieldValue}
|
||||
</Typography>
|
||||
</Box>
|
||||
<IconButton
|
||||
sx={{
|
||||
m: "auto",
|
||||
}}
|
||||
onClick={deleteHC}
|
||||
>
|
||||
<Trash />
|
||||
</IconButton>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@ -1,8 +1,9 @@
|
||||
import { Box, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { FC } from "react";
|
||||
import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock";
|
||||
import { CustomSelect } from "../../../../../components/CustomSelect/CustomSelect";
|
||||
import { MinifiedData } from "../types";
|
||||
import { StepButtonsBlock } from "./StepButtonsBlock";
|
||||
import { CustomSelect } from "../../../../components/CustomSelect/CustomSelect";
|
||||
import { MinifiedData } from "./types";
|
||||
import { ModalTitle } from "./ModalTitle";
|
||||
|
||||
type Props = {
|
||||
users: MinifiedData[];
|
||||
@ -10,6 +11,14 @@ type Props = {
|
||||
handleNextStep: () => void;
|
||||
selectedDealUser: string | null;
|
||||
setSelectedDealPerformer: (value: string | null) => void;
|
||||
|
||||
titleProps: {
|
||||
step: number;
|
||||
title: string;
|
||||
desc: string;
|
||||
toSettings: () => void;
|
||||
}
|
||||
onScrollUsers: () => void;
|
||||
};
|
||||
|
||||
export const DealPerformers: FC<Props> = ({
|
||||
@ -18,27 +27,34 @@ export const DealPerformers: FC<Props> = ({
|
||||
handleNextStep,
|
||||
selectedDealUser,
|
||||
setSelectedDealPerformer,
|
||||
onScrollUsers,
|
||||
titleProps,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
height: "100%",
|
||||
overflow: "auto",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ width: "100%", marginTop: "20px", zIndex: 3 }}>
|
||||
<Box sx={{ width: "100%", zIndex: 3 }}>
|
||||
<ModalTitle
|
||||
{...titleProps}
|
||||
/>
|
||||
<CustomSelect
|
||||
items={users}
|
||||
selectedItemId={selectedDealUser}
|
||||
setSelectedItem={setSelectedDealPerformer}
|
||||
handleScroll={() => {}}
|
||||
handleScroll={onScrollUsers}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
@ -53,5 +69,6 @@ export const DealPerformers: FC<Props> = ({
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -6,7 +6,7 @@ interface Props {
|
||||
close: () => void;
|
||||
}
|
||||
|
||||
export const AmoDeleteTagQuestion: FC<Props> = ({ close, deleteItem }) => {
|
||||
export const DeleteTagQuestion: FC<Props> = ({ close, deleteItem }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
@ -6,87 +6,77 @@ import AccountSetting from "@icons/AccountSetting";
|
||||
|
||||
type AmoModalTitleProps = {
|
||||
step: number;
|
||||
steps: { title: string; isSettingsAvailable: boolean }[];
|
||||
isSettingsBlock?: boolean;
|
||||
setIsSettingsBlock: (value: boolean) => void;
|
||||
setStep: (value: number) => void;
|
||||
startRemoveAccount: () => void;
|
||||
title: string;
|
||||
desc: string;
|
||||
toSettings: () => void;
|
||||
};
|
||||
|
||||
export const AmoModalTitle: FC<AmoModalTitleProps> = ({
|
||||
export const ModalTitle: FC<AmoModalTitleProps> = ({
|
||||
step,
|
||||
steps,
|
||||
setIsSettingsBlock,
|
||||
isSettingsBlock,
|
||||
setStep,
|
||||
startRemoveAccount,
|
||||
title,
|
||||
desc,
|
||||
toSettings,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
|
||||
const handleClick = useCallback(async () => {
|
||||
if (isSettingsBlock) {
|
||||
startRemoveAccount();
|
||||
setIsSettingsBlock(false);
|
||||
setStep(0);
|
||||
return;
|
||||
}
|
||||
setIsSettingsBlock(true);
|
||||
}, [isSettingsBlock, setIsSettingsBlock, setStep]);
|
||||
|
||||
const btnText = useMemo(() => {
|
||||
return isSettingsBlock ? "Сменить аккаунт" : "Мои настройки";
|
||||
}, [isSettingsBlock]);
|
||||
|
||||
return (
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between" }}>
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between", width: "100%" }}>
|
||||
<Box>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: isMobile ? "18px" : "24px",
|
||||
color: theme.palette.grey3.main,
|
||||
fontWeight: "400",
|
||||
fontWeight: "500",
|
||||
lineHeight: "1",
|
||||
}}
|
||||
>
|
||||
{isSettingsBlock ? "Мои настройки" : steps[step].title}
|
||||
{title}
|
||||
</Typography>
|
||||
{isSettingsBlock || (
|
||||
{
|
||||
desc &&
|
||||
<Typography
|
||||
sx={{
|
||||
color: theme.palette.grey2.main,
|
||||
fontWeight: "400",
|
||||
marginTop: "4px",
|
||||
fontSize: "14px",
|
||||
lineHeight: "1",
|
||||
color: "#4D4D4D",
|
||||
fontSize: "16px",
|
||||
m: "5px 0 15px 0",
|
||||
whiteSpace: "break-spaces",
|
||||
width: "90%"
|
||||
}}
|
||||
>
|
||||
Шаг {step + 1}
|
||||
{desc}
|
||||
</Typography>
|
||||
)}
|
||||
}
|
||||
<Typography
|
||||
sx={{
|
||||
color: theme.palette.grey2.main,
|
||||
fontWeight: "400",
|
||||
marginTop: "4px",
|
||||
fontSize: "14px",
|
||||
lineHeight: "1",
|
||||
}}
|
||||
>
|
||||
{step} шаг
|
||||
</Typography>
|
||||
</Box>
|
||||
{steps[step].isSettingsAvailable && (
|
||||
|
||||
|
||||
<Box>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={
|
||||
isSettingsBlock ? (
|
||||
<AccountSetting
|
||||
color={theme.palette.brightPurple.main}
|
||||
height={"20px"}
|
||||
width={"20px"}
|
||||
/>
|
||||
) : (
|
||||
<GearIcon
|
||||
color={theme.palette.brightPurple.main}
|
||||
height={"24px"}
|
||||
width={"24px"}
|
||||
/>
|
||||
)
|
||||
<GearIcon
|
||||
color={theme.palette.brightPurple.main}
|
||||
height={"24px"}
|
||||
width={"24px"}
|
||||
/>
|
||||
}
|
||||
onClick={handleClick}
|
||||
onClick={toSettings}
|
||||
sx={{
|
||||
padding: isMobile ? "10px" : "10px 20px",
|
||||
width: "fit-content",
|
||||
height: "44px",
|
||||
padding: "0",
|
||||
width: isMobile ? "44px" : "205px",
|
||||
minWidth: isMobile ? "44px" : "auto",
|
||||
backgroundColor: "transparent",
|
||||
color: theme.palette.brightPurple.main,
|
||||
"& .MuiButton-startIcon": {
|
||||
@ -115,9 +105,9 @@ export const AmoModalTitle: FC<AmoModalTitleProps> = ({
|
||||
},
|
||||
}}
|
||||
>
|
||||
{isMobile ? "" : btnText}
|
||||
{isMobile ? "" : "Мои настройки"}
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,108 @@
|
||||
import { Box, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { FC } from "react";
|
||||
import { StepButtonsBlock } from "./StepButtonsBlock";
|
||||
import { CustomSelect } from "../../../../components/CustomSelect/CustomSelect";
|
||||
import { CustomRadioGroup } from "../../../../components/CustomRadioGroup/CustomRadioGroup";
|
||||
import { MinifiedData } from "./types";
|
||||
import { ModalTitle } from "./ModalTitle";
|
||||
|
||||
type Props = {
|
||||
users: MinifiedData[];
|
||||
steps: MinifiedData[];
|
||||
handlePrevStep: () => void;
|
||||
handleNextStep: () => void;
|
||||
selectedDealUser: string | null;
|
||||
setSelectedDealPerformer: (value: string | null) => void;
|
||||
selectedStep: string | null;
|
||||
setSelectedStep: (value: string | null) => void;
|
||||
|
||||
titleProps: {
|
||||
step: number;
|
||||
title: string;
|
||||
desc: string;
|
||||
toSettings: () => void;
|
||||
}
|
||||
onScroll: () => void;
|
||||
onScrollUsers: () => void;
|
||||
};
|
||||
|
||||
export const PipelineSteps: FC<Props> = ({
|
||||
users,
|
||||
selectedDealUser,
|
||||
setSelectedDealPerformer,
|
||||
|
||||
steps,
|
||||
selectedStep,
|
||||
setSelectedStep,
|
||||
onScroll,
|
||||
onScrollUsers,
|
||||
|
||||
|
||||
handlePrevStep,
|
||||
handleNextStep,
|
||||
|
||||
titleProps
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
height: "100%",
|
||||
overflow: "auto",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
height: "100%",
|
||||
overflow: "auto",
|
||||
zIndex: 3,
|
||||
width: "100%",
|
||||
}}>
|
||||
<Box sx={{ width: "100%", zIndex: 3 }}>
|
||||
<ModalTitle
|
||||
{...titleProps}
|
||||
/>
|
||||
<CustomSelect
|
||||
items={users}
|
||||
selectedItemId={selectedDealUser}
|
||||
setSelectedItem={setSelectedDealPerformer}
|
||||
handleScroll={onScrollUsers}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "13px",
|
||||
flexGrow: 1,
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<CustomRadioGroup
|
||||
items={steps}
|
||||
selectedItemId={selectedStep}
|
||||
setSelectedItem={setSelectedStep}
|
||||
handleScroll={onScroll}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
alignSelf: "end",
|
||||
}}
|
||||
>
|
||||
<StepButtonsBlock
|
||||
onLargeBtnClick={handleNextStep}
|
||||
onSmallBtnClick={handlePrevStep}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -1,81 +0,0 @@
|
||||
import { Box, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { FC } from "react";
|
||||
import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock";
|
||||
import { CustomSelect } from "../../../../../components/CustomSelect/CustomSelect";
|
||||
import { CustomRadioGroup } from "../../../../../components/CustomRadioGroup/CustomRadioGroup";
|
||||
import { MinifiedData } from "../types";
|
||||
|
||||
type Props = {
|
||||
users: MinifiedData[];
|
||||
steps: MinifiedData[];
|
||||
handlePrevStep: () => void;
|
||||
handleNextStep: () => void;
|
||||
selectedDealUser: string | null;
|
||||
setSelectedDealPerformer: (value: string | null) => void;
|
||||
selectedStep: string | null;
|
||||
setSelectedStep: (value: string | null) => void;
|
||||
};
|
||||
|
||||
export const PipelineSteps: FC<Props> = ({
|
||||
users,
|
||||
selectedDealUser,
|
||||
setSelectedDealPerformer,
|
||||
|
||||
steps,
|
||||
selectedStep,
|
||||
setSelectedStep,
|
||||
|
||||
handlePrevStep,
|
||||
handleNextStep,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
height: "100%",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ width: "100%", marginTop: "20px", zIndex: 3 }}>
|
||||
<CustomSelect
|
||||
items={users}
|
||||
selectedItemId={selectedDealUser}
|
||||
setSelectedItem={setSelectedDealPerformer}
|
||||
handleScroll={() => {}}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "20px",
|
||||
flexGrow: 1,
|
||||
width: "100%",
|
||||
height: "346px",
|
||||
}}
|
||||
>
|
||||
<CustomRadioGroup
|
||||
items={steps}
|
||||
selectedItemId={selectedStep}
|
||||
setSelectedItem={setSelectedStep}
|
||||
handleScroll={() => {}}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "20px",
|
||||
alignSelf: "end",
|
||||
}}
|
||||
>
|
||||
<StepButtonsBlock
|
||||
onLargeBtnClick={handleNextStep}
|
||||
onSmallBtnClick={handlePrevStep}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
105
src/pages/IntegrationsPage/IntegrationsModal/Amo/Pipelines.tsx
Normal file
105
src/pages/IntegrationsPage/IntegrationsModal/Amo/Pipelines.tsx
Normal file
@ -0,0 +1,105 @@
|
||||
import { Box, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { FC } from "react";
|
||||
import { StepButtonsBlock } from "./StepButtonsBlock";
|
||||
import { CustomSelect } from "../../../../components/CustomSelect/CustomSelect";
|
||||
import { CustomRadioGroup } from "../../../../components/CustomRadioGroup/CustomRadioGroup";
|
||||
import { MinifiedData } from "./types";
|
||||
import { ModalTitle } from "./ModalTitle";
|
||||
|
||||
type Props = {
|
||||
pipelines: MinifiedData[];
|
||||
users: MinifiedData[];
|
||||
handlePrevStep: () => void;
|
||||
handleNextStep: () => void;
|
||||
selectedDealUser: string | null;
|
||||
setSelectedDealPerformer: (value: string | null) => void;
|
||||
selectedPipeline: string | null;
|
||||
setSelectedPipeline: (value: string | null) => void;
|
||||
|
||||
titleProps: {
|
||||
step: number;
|
||||
title: string;
|
||||
desc: string;
|
||||
toSettings: () => void;
|
||||
}
|
||||
onScroll: () => void;
|
||||
onScrollUsers: () => void;
|
||||
};
|
||||
|
||||
export const Pipelines: FC<Props> = ({
|
||||
pipelines,
|
||||
selectedPipeline,
|
||||
setSelectedPipeline,
|
||||
titleProps,
|
||||
|
||||
users,
|
||||
selectedDealUser,
|
||||
setSelectedDealPerformer,
|
||||
onScroll,
|
||||
onScrollUsers,
|
||||
|
||||
handlePrevStep,
|
||||
handleNextStep,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
height: "100%",
|
||||
overflow: "auto",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
height: "100%",
|
||||
overflow: "auto",
|
||||
zIndex: 3,
|
||||
width: "100%",
|
||||
}}>
|
||||
<Box sx={{ width: "100%", zIndex: 3 }}>
|
||||
<ModalTitle
|
||||
{...titleProps}
|
||||
/>
|
||||
<CustomSelect
|
||||
items={users}
|
||||
selectedItemId={selectedDealUser}
|
||||
setSelectedItem={setSelectedDealPerformer}
|
||||
handleScroll={onScrollUsers}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "13px",
|
||||
flexGrow: 1,
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<CustomRadioGroup
|
||||
items={pipelines}
|
||||
selectedItemId={selectedPipeline}
|
||||
setSelectedItem={setSelectedPipeline}
|
||||
handleScroll={onScroll}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
alignSelf: "end",
|
||||
}}
|
||||
>
|
||||
<StepButtonsBlock
|
||||
onLargeBtnClick={handleNextStep}
|
||||
onSmallBtnClick={handlePrevStep}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -1,80 +0,0 @@
|
||||
import { Box, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { FC } from "react";
|
||||
import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock";
|
||||
import { CustomSelect } from "../../../../../components/CustomSelect/CustomSelect";
|
||||
import { CustomRadioGroup } from "../../../../../components/CustomRadioGroup/CustomRadioGroup";
|
||||
import { MinifiedData } from "../types";
|
||||
|
||||
type Props = {
|
||||
pipelines: MinifiedData[];
|
||||
users: MinifiedData[];
|
||||
handlePrevStep: () => void;
|
||||
handleNextStep: () => void;
|
||||
selectedDealUser: string | null;
|
||||
setSelectedDealPerformer: (value: string | null) => void;
|
||||
selectedPipeline: string | null;
|
||||
setSelectedPipeline: (value: string | null) => void;
|
||||
};
|
||||
|
||||
export const Pipelines: FC<Props> = ({
|
||||
pipelines,
|
||||
selectedPipeline,
|
||||
setSelectedPipeline,
|
||||
|
||||
users,
|
||||
selectedDealUser,
|
||||
setSelectedDealPerformer,
|
||||
|
||||
handlePrevStep,
|
||||
handleNextStep,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
height: "100%",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ width: "100%", marginTop: "20px", zIndex: 3 }}>
|
||||
<CustomSelect
|
||||
items={users}
|
||||
selectedItemId={selectedDealUser}
|
||||
setSelectedItem={setSelectedDealPerformer}
|
||||
handleScroll={() => {}}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "20px",
|
||||
flexGrow: 1,
|
||||
width: "100%",
|
||||
height: "346px",
|
||||
}}
|
||||
>
|
||||
<CustomRadioGroup
|
||||
items={pipelines}
|
||||
selectedItemId={selectedPipeline}
|
||||
setSelectedItem={setSelectedPipeline}
|
||||
handleScroll={() => {}}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "20px",
|
||||
alignSelf: "end",
|
||||
}}
|
||||
>
|
||||
<StepButtonsBlock
|
||||
onLargeBtnClick={handleNextStep}
|
||||
onSmallBtnClick={handlePrevStep}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@ -4,8 +4,10 @@ import { ItemDetailsView } from "./ItemDetailsView/ItemDetailsView";
|
||||
import { Box } from "@mui/material";
|
||||
import { MinifiedData, QuestionKeys, SelectedQuestions, TagKeys, TagQuestionHC } from "../types";
|
||||
import { EntitiesQuestions } from "./EntitiesQuestions";
|
||||
import { diffArr } from "../AmoCRMModal";
|
||||
import { diffArr } from "..";
|
||||
import { DataConstrictor } from "../Components/DataConstrictor";
|
||||
import { ModalTitle } from "../ModalTitle";
|
||||
import { StepButtonsBlock } from "../StepButtonsBlock";
|
||||
|
||||
type Props = {
|
||||
selectedCurrentFields: MinifiedData[] | [];
|
||||
@ -18,6 +20,12 @@ type Props = {
|
||||
handleNextStep: () => void;
|
||||
FieldsAllowedFC: MinifiedData[]
|
||||
setSelectedCurrentFields: (value: MinifiedData[]) => void;
|
||||
titleProps: {
|
||||
step: number;
|
||||
title: string;
|
||||
toSettings: () => void;
|
||||
}
|
||||
onScroll: () => void;
|
||||
};
|
||||
export type QuestionPair = {
|
||||
question: string,
|
||||
@ -40,7 +48,9 @@ export const AmoQuestions: FC<Props> = ({
|
||||
handleNextStep,
|
||||
openDelete,
|
||||
FieldsAllowedFC,
|
||||
setSelectedCurrentFields
|
||||
setSelectedCurrentFields,
|
||||
onScroll,
|
||||
titleProps,
|
||||
}) => {
|
||||
const [isSelection, setIsSelection] = useState<boolean>(false);
|
||||
const [activeScope, setActiveScope] = useState<QuestionKeys | null>(null);
|
||||
@ -109,17 +119,6 @@ export const AmoQuestions: FC<Props> = ({
|
||||
const [sortedFieldsItems, setSortedFieldsItems] = useState<MinifiedData[]>(fieldsItems);
|
||||
const [sortedquestionsItems, setSortedquestionsItems] = useState<MinifiedData[]>(questionsItems);
|
||||
|
||||
console.log("допущенные ФОРМА КОНТАКТОВ")
|
||||
console.log(FieldsAllowedFC)
|
||||
console.log("фильтрованные")
|
||||
console.log(sortedFieldsAllowedFC)
|
||||
console.log("")
|
||||
console.log("допущенные вапросы")
|
||||
console.log(questionsItems)
|
||||
console.log("фильтрованные")
|
||||
console.log(sortedquestionsItems)
|
||||
|
||||
|
||||
const startConstrictor = (substr: string) => {
|
||||
const a = FieldsAllowedFC.filter((mData) => mData.title.toLowerCase().startsWith(substr.toLowerCase()))
|
||||
const b = fieldsItems.filter((mData) => mData.title.toLowerCase().startsWith(substr.toLowerCase()))
|
||||
@ -135,78 +134,93 @@ export const AmoQuestions: FC<Props> = ({
|
||||
setSortedquestionsItems(questionsItems);
|
||||
}, [activeScope])
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
{isSelection && activeScope !== null ? (
|
||||
<>
|
||||
<DataConstrictor
|
||||
isError={false}
|
||||
constrictor={startConstrictor}
|
||||
/>
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
height: "calc( 100% - 70px )",
|
||||
overflow: "auto"
|
||||
}}
|
||||
>
|
||||
<ModalTitle
|
||||
{...titleProps}
|
||||
desc={isSelection && activeScope !== null ? "На этом этапе вы можете соотнести ваше ранее созданное поле с вопросом из квиза или добавить новое поле" : "На этом этапе вы можете добавить в поля соответствующие вопросы"}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
{isSelection && activeScope !== null ? (
|
||||
// Здесь выбираем элемент в табличку
|
||||
<>
|
||||
<DataConstrictor
|
||||
isError={false}
|
||||
constrictor={startConstrictor}
|
||||
/>
|
||||
<EntitiesQuestions
|
||||
FieldsAllowedFC={sortedFieldsAllowedFC}
|
||||
fieldsItems={sortedFieldsItems}
|
||||
items={(sortedquestionsItems.length === 0) ? [] : diffArr(sortedquestionsItems, selectedQuestions[activeScope])}
|
||||
selectedItemId={selectedQuestion}
|
||||
setSelectedQuestion={setSelectedQuestion}
|
||||
selectedField={selectedField}
|
||||
selectedCurrentFields={selectedCurrentFields}
|
||||
setSelectedField={setSelectedField}
|
||||
activeScope={activeScope}
|
||||
setIsCurrentFields={setIsCurrentFields}
|
||||
isCurrentFields={isCurrentFields}
|
||||
handleScroll={onScroll}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
// Табличка
|
||||
<ItemDetailsView
|
||||
items={[...questionsItems, ...FieldsAllowedFC]}
|
||||
setActiveScope={setActiveScope}
|
||||
selectedQuestions={{
|
||||
Lead: [...selectedQuestions.Lead, ...SCFworld.Lead],
|
||||
Company: [...selectedQuestions.Company, ...SCFworld.Company],
|
||||
Customer: [...selectedQuestions.Customer, ...SCFworld.Customer],
|
||||
Contact: [...selectedQuestions.Contact, ...SCFworld.Contact]
|
||||
}}
|
||||
setIsSelection={setIsSelection}
|
||||
deleteHC={handleDelete}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* табличка */}
|
||||
|
||||
<EntitiesQuestions
|
||||
FieldsAllowedFC={sortedFieldsAllowedFC}
|
||||
fieldsItems={sortedFieldsItems}
|
||||
items={(sortedquestionsItems.length === 0) ? [] : diffArr(sortedquestionsItems, selectedQuestions[activeScope])}
|
||||
selectedItemId={selectedQuestion}
|
||||
setSelectedQuestion={setSelectedQuestion}
|
||||
selectedField={selectedField}
|
||||
selectedCurrentFields={selectedCurrentFields}
|
||||
setSelectedField={setSelectedField}
|
||||
onSmallBtnClick={() => {
|
||||
setActiveScope(null);
|
||||
setIsSelection(false);
|
||||
}}
|
||||
<Box
|
||||
sx={{
|
||||
alignSelf: "end",
|
||||
}}
|
||||
>
|
||||
{isSelection && activeScope !== null ?
|
||||
<StepButtonsBlock
|
||||
onLargeBtnClick={() => {
|
||||
handleAdd();
|
||||
setActiveScope(null);
|
||||
setIsSelection(false);
|
||||
}}
|
||||
activeScope={activeScope}
|
||||
setIsCurrentFields={setIsCurrentFields}
|
||||
isCurrentFields={isCurrentFields}
|
||||
largeBtnText={"Добавить"}
|
||||
onSmallBtnClick={() => {
|
||||
setActiveScope(null);
|
||||
setIsSelection(false);
|
||||
}}
|
||||
smallBtnText={"Отменить"}
|
||||
/>
|
||||
</>
|
||||
// Здесь выбираем элемент в табличку
|
||||
// <ItemsSelectionView
|
||||
// items={questionsItems}
|
||||
// selectedItemId={selectedQuestion}
|
||||
// setSelectedItem={setSelectedQuestion}
|
||||
// onSmallBtnClick={() => {
|
||||
// setActiveScope(null);
|
||||
// setIsSelection(false);
|
||||
// }}
|
||||
// onLargeBtnClick={() => {
|
||||
// handleAdd();
|
||||
// setActiveScope(null);
|
||||
// setIsSelection(false);
|
||||
// }}
|
||||
// />
|
||||
) : (
|
||||
// Табличка
|
||||
<ItemDetailsView
|
||||
items={[...questionsItems, ...FieldsAllowedFC]}
|
||||
setActiveScope={setActiveScope}
|
||||
selectedQuestions={{
|
||||
Lead: [...selectedQuestions.Lead, ...SCFworld.Lead],
|
||||
Company: [...selectedQuestions.Company, ...SCFworld.Company],
|
||||
Customer: [...selectedQuestions.Customer, ...SCFworld.Customer],
|
||||
Contact: [...selectedQuestions.Contact, ...SCFworld.Contact]
|
||||
}}
|
||||
setIsSelection={setIsSelection}
|
||||
handleLargeBtn={handleNextStep}
|
||||
handleSmallBtn={handlePrevStep}
|
||||
deleteHC={handleDelete}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
:
|
||||
<StepButtonsBlock
|
||||
onSmallBtnClick={handlePrevStep}
|
||||
onLargeBtnClick={handleNextStep}
|
||||
largeBtnText={"Сохранить"}
|
||||
/>
|
||||
|
||||
}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -1,8 +1,8 @@
|
||||
import { CustomRadioGroup } from "@/components/CustomRadioGroup/CustomRadioGroup"
|
||||
import {Box, Typography, useMediaQuery, useTheme} from "@mui/material"
|
||||
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"
|
||||
import { MinifiedData } from "../types";
|
||||
import {CustomSelect} from "@/components/CustomSelect/CustomSelect";
|
||||
import {CurrentFieldSelect} from "@/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/CurrentFieldSelectMobile";
|
||||
import { CustomSelect } from "@/components/CustomSelect/CustomSelect";
|
||||
import { CurrentFieldSelect } from "@/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/CurrentFieldSelectMobile";
|
||||
|
||||
interface Props {
|
||||
items: MinifiedData[];
|
||||
@ -11,6 +11,7 @@ interface Props {
|
||||
currentQuestion: string;
|
||||
setCurrentField: (value: string) => void;
|
||||
setCurrentQuestion: (value: string) => void;
|
||||
handleScroll: () => void;
|
||||
}
|
||||
export const CurrentFields = ({
|
||||
items,
|
||||
@ -19,6 +20,7 @@ export const CurrentFields = ({
|
||||
currentQuestion,
|
||||
setCurrentField,
|
||||
setCurrentQuestion,
|
||||
handleScroll,
|
||||
}: Props) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
@ -53,18 +55,18 @@ export const CurrentFields = ({
|
||||
{isMobile &&
|
||||
<CurrentFieldSelect
|
||||
items={fieldsItems}
|
||||
selectedItemId={currentField
|
||||
} setSelectedItem={setCurrentField}
|
||||
handleScroll={() => { }}/>
|
||||
selectedItemId={currentField}
|
||||
setSelectedItem={setCurrentField}
|
||||
handleScroll={handleScroll} />
|
||||
}
|
||||
{!isMobile &&
|
||||
<CustomRadioGroup
|
||||
items={fieldsItems}
|
||||
selectedItemId={currentField}
|
||||
setSelectedItem={setCurrentField}
|
||||
handleScroll={() => { }}
|
||||
activeScope={undefined}
|
||||
/>
|
||||
<CustomRadioGroup
|
||||
items={fieldsItems}
|
||||
selectedItemId={currentField}
|
||||
setSelectedItem={setCurrentField}
|
||||
handleScroll={handleScroll}
|
||||
activeScope={undefined}
|
||||
/>
|
||||
}
|
||||
|
||||
</Box>
|
||||
@ -85,20 +87,20 @@ export const CurrentFields = ({
|
||||
}}
|
||||
>Выберите вопрос для этого поля</Typography>
|
||||
{isMobile &&
|
||||
<CurrentFieldSelect
|
||||
items={items}
|
||||
selectedItemId={currentQuestion}
|
||||
setSelectedItem={setCurrentQuestion}
|
||||
handleScroll={() => { }}/>
|
||||
<CurrentFieldSelect
|
||||
items={items}
|
||||
selectedItemId={currentQuestion}
|
||||
setSelectedItem={setCurrentQuestion}
|
||||
handleScroll={() => { }} />
|
||||
}
|
||||
{!isMobile &&
|
||||
<CustomRadioGroup
|
||||
items={items}
|
||||
selectedItemId={currentQuestion}
|
||||
setSelectedItem={setCurrentQuestion}
|
||||
handleScroll={() => { }}
|
||||
activeScope={undefined}
|
||||
/>
|
||||
<CustomRadioGroup
|
||||
items={items}
|
||||
selectedItemId={currentQuestion}
|
||||
setSelectedItem={setCurrentQuestion}
|
||||
handleScroll={() => { }}
|
||||
activeScope={undefined}
|
||||
/>
|
||||
}
|
||||
|
||||
</Box>
|
||||
@ -1,11 +1,11 @@
|
||||
import {Box, Button, useMediaQuery, useTheme} from "@mui/material"
|
||||
import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"
|
||||
import { StepButtonsBlock } from "../StepButtonsBlock"
|
||||
import { FC, useState } from "react";
|
||||
import { MinifiedData, TagKeys } from "../types";
|
||||
import { CurrentFields } from "./CurrentFields";
|
||||
import { NewFields } from "./NewFields";
|
||||
import { QuestionPair } from "./AmoQuestions";
|
||||
import { diffArr } from "../AmoCRMModal";
|
||||
import { diffArr } from "..";
|
||||
|
||||
type ItemsSelectionViewProps = {
|
||||
items: MinifiedData[] | [];
|
||||
@ -14,9 +14,7 @@ type ItemsSelectionViewProps = {
|
||||
setSelectedQuestion: (value: string | null) => void;
|
||||
selectedField?: string | null;
|
||||
setSelectedField: (value: string | null) => void;
|
||||
handleScroll?: () => void;
|
||||
onLargeBtnClick: () => void;
|
||||
onSmallBtnClick: () => void;
|
||||
handleScroll: () => void;
|
||||
activeScope: TagKeys;
|
||||
FieldsAllowedFC: MinifiedData[];
|
||||
selectedCurrentFields: MinifiedData[];
|
||||
@ -31,8 +29,6 @@ export const EntitiesQuestions: FC<ItemsSelectionViewProps> = ({
|
||||
selectedField,
|
||||
setSelectedField,
|
||||
handleScroll,
|
||||
onLargeBtnClick,
|
||||
onSmallBtnClick,
|
||||
activeScope,
|
||||
FieldsAllowedFC,
|
||||
selectedCurrentFields,
|
||||
@ -41,13 +37,6 @@ export const EntitiesQuestions: FC<ItemsSelectionViewProps> = ({
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
console.log("--------------")
|
||||
console.log("EntitiesQuestions")
|
||||
console.log("вопросы")
|
||||
console.log(items)
|
||||
console.log("ФК")
|
||||
console.log(FieldsAllowedFC)
|
||||
console.log("------------------------------")
|
||||
|
||||
return (
|
||||
<Box
|
||||
@ -105,6 +94,7 @@ export const EntitiesQuestions: FC<ItemsSelectionViewProps> = ({
|
||||
currentQuestion={selectedItemId}
|
||||
setCurrentField={setSelectedField}
|
||||
setCurrentQuestion={setSelectedQuestion}
|
||||
handleScroll={handleScroll}
|
||||
/>
|
||||
:
|
||||
<NewFields
|
||||
@ -114,21 +104,6 @@ export const EntitiesQuestions: FC<ItemsSelectionViewProps> = ({
|
||||
/>
|
||||
}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "20px",
|
||||
alignSelf: "end",
|
||||
}}
|
||||
>
|
||||
<StepButtonsBlock
|
||||
onLargeBtnClick={() => {
|
||||
onLargeBtnClick()
|
||||
}}
|
||||
largeBtnText={"Добавить"}
|
||||
onSmallBtnClick={onSmallBtnClick}
|
||||
smallBtnText={"Отменить"}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import { Box, useTheme } from "@mui/material";
|
||||
import { ItemForQuestions } from "../ItemForQuestions";
|
||||
import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock";
|
||||
import { StepButtonsBlock } from "../../StepButtonsBlock";
|
||||
import { FC } from "react";
|
||||
import { MinifiedData, QuestionKeys, SelectedQuestions } from "../../types";
|
||||
|
||||
@ -9,8 +9,6 @@ type TitleKeys = "Contact" | "Company" | "Lead" | "Customer";
|
||||
type ItemDetailsViewProps = {
|
||||
items: MinifiedData[];
|
||||
setIsSelection: (value: boolean) => void;
|
||||
handleSmallBtn: () => void;
|
||||
handleLargeBtn: () => void;
|
||||
selectedQuestions: SelectedQuestions;
|
||||
setActiveScope: (value: QuestionKeys | null) => void;
|
||||
deleteHC: (id: string, scope: QuestionKeys) => void;
|
||||
@ -18,8 +16,6 @@ type ItemDetailsViewProps = {
|
||||
|
||||
export const ItemDetailsView: FC<ItemDetailsViewProps> = ({
|
||||
items,
|
||||
handleSmallBtn,
|
||||
handleLargeBtn,
|
||||
selectedQuestions,
|
||||
setIsSelection,
|
||||
setActiveScope,
|
||||
@ -68,18 +64,6 @@ export const ItemDetailsView: FC<ItemDetailsViewProps> = ({
|
||||
))}
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "20px",
|
||||
alignSelf: "end",
|
||||
}}
|
||||
>
|
||||
<StepButtonsBlock
|
||||
onSmallBtnClick={handleSmallBtn}
|
||||
onLargeBtnClick={handleLargeBtn}
|
||||
largeBtnText={"Сохранить"}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
import { Box } from "@mui/material";
|
||||
import { CustomRadioGroup } from "../../../../../../components/CustomRadioGroup/CustomRadioGroup";
|
||||
import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock";
|
||||
import { StepButtonsBlock } from "../../StepButtonsBlock";
|
||||
import { FC } from "react";
|
||||
import { MinifiedData, TagKeys } from "../../types";
|
||||
|
||||
@ -9,8 +9,6 @@ type ItemsSelectionViewProps = {
|
||||
selectedItemId?: string | null;
|
||||
setSelectedItem: (value: string | null) => void;
|
||||
handleScroll?: () => void;
|
||||
onLargeBtnClick: () => void;
|
||||
onSmallBtnClick: () => void;
|
||||
activeScope: TagKeys;
|
||||
};
|
||||
|
||||
@ -19,8 +17,6 @@ export const ItemsSelectionView: FC<ItemsSelectionViewProps> = ({
|
||||
selectedItemId,
|
||||
setSelectedItem,
|
||||
handleScroll,
|
||||
onLargeBtnClick,
|
||||
onSmallBtnClick,
|
||||
activeScope,
|
||||
}) => {
|
||||
return (
|
||||
@ -49,19 +45,6 @@ export const ItemsSelectionView: FC<ItemsSelectionViewProps> = ({
|
||||
activeScope={activeScope}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "20px",
|
||||
alignSelf: "end",
|
||||
}}
|
||||
>
|
||||
<StepButtonsBlock
|
||||
onLargeBtnClick={onLargeBtnClick}
|
||||
largeBtnText={"Добавить"}
|
||||
onSmallBtnClick={onSmallBtnClick}
|
||||
smallBtnText={"Отменить"}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@ -10,7 +10,7 @@ interface Props {
|
||||
|
||||
}
|
||||
|
||||
export const AmoRemoveAccount: FC<Props> = ({
|
||||
export const RemoveAccount: FC<Props> = ({
|
||||
stopThisPage,
|
||||
handleCloseModal,
|
||||
|
||||
@ -1,81 +0,0 @@
|
||||
import { FC } from "react";
|
||||
import { Box, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock";
|
||||
import { SettingItem } from "./SettingItem/SettingItem";
|
||||
import { SelectedQuestions, SelectedTags } from "../types";
|
||||
|
||||
type AmoSettingsBlockProps = {
|
||||
stepTitles: string[];
|
||||
setStep: (value: number) => void;
|
||||
setIsSettingsBlock: (value: boolean) => void;
|
||||
selectedFunnel: string | null;
|
||||
selectedStage: string | null;
|
||||
selectedDealUser: string | null;
|
||||
selectedQuestions: SelectedQuestions;
|
||||
selectedTags: SelectedTags;
|
||||
};
|
||||
|
||||
export const AmoSettingsBlock: FC<AmoSettingsBlockProps> = ({
|
||||
stepTitles,
|
||||
setStep,
|
||||
setIsSettingsBlock,
|
||||
selectedFunnel,
|
||||
selectedDealUser,
|
||||
selectedStage,
|
||||
selectedQuestions,
|
||||
selectedTags,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
height: "100%",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "10px",
|
||||
width: "100%",
|
||||
height: "443px",
|
||||
borderRadius: "10px",
|
||||
padding: " 0 20px",
|
||||
boxShadow: "0 0 20px rgba(0, 0, 0, 0.15)",
|
||||
overflowY: "auto",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
{stepTitles &&
|
||||
stepTitles.map((title, index) => (
|
||||
<SettingItem
|
||||
step={index}
|
||||
title={title}
|
||||
setIsSettingsBlock={setIsSettingsBlock}
|
||||
setStep={setStep}
|
||||
selectedDealUser={selectedDealUser}
|
||||
selectedFunnel={selectedFunnel}
|
||||
selectedStage={selectedStage}
|
||||
selectedQuestions={selectedQuestions}
|
||||
selectedTags={selectedTags}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "20px",
|
||||
alignSelf: "end",
|
||||
}}
|
||||
>
|
||||
<StepButtonsBlock
|
||||
onSmallBtnClick={() => setIsSettingsBlock(false)}
|
||||
isLargeBtnMissing={true}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@ -9,8 +9,7 @@ import { SelectedQuestions, SelectedTags } from "../../types";
|
||||
type SettingItemProps = {
|
||||
step: number;
|
||||
title: string;
|
||||
setStep: (value: number) => void;
|
||||
setIsSettingsBlock: (value: boolean) => void;
|
||||
setStep: (step: number) => void;
|
||||
selectedFunnelPerformer: string | null;
|
||||
selectedFunnel: string | null;
|
||||
selectedStagePerformer: string | null;
|
||||
@ -24,7 +23,6 @@ export const SettingItem: FC<SettingItemProps> = ({
|
||||
step,
|
||||
title,
|
||||
setStep,
|
||||
setIsSettingsBlock,
|
||||
selectedFunnelPerformer,
|
||||
selectedFunnel,
|
||||
selectedStagePerformer,
|
||||
@ -34,6 +32,7 @@ export const SettingItem: FC<SettingItemProps> = ({
|
||||
selectedTags,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
console.log(step)
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
if (step === 0) {
|
||||
return;
|
||||
@ -146,8 +145,7 @@ export const SettingItem: FC<SettingItemProps> = ({
|
||||
<SettingItemHeader
|
||||
title={title}
|
||||
step={step}
|
||||
setIsSettingsBlock={setIsSettingsBlock}
|
||||
setStep={setStep}
|
||||
setStep={() => setStep(step)}
|
||||
/>
|
||||
<Box>{SettingsContent}</Box>
|
||||
</Box>
|
||||
|
||||
@ -6,23 +6,16 @@ import { FC } from "react";
|
||||
type SettingItemHeaderProps = {
|
||||
title: string;
|
||||
step: number;
|
||||
setStep: (value: number) => void;
|
||||
setIsSettingsBlock: (value: boolean) => void;
|
||||
setStep: () => void;
|
||||
};
|
||||
|
||||
export const SettingItemHeader: FC<SettingItemHeaderProps> = ({
|
||||
title,
|
||||
step,
|
||||
setStep,
|
||||
setIsSettingsBlock,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const handleClick = () => {
|
||||
setStep(step);
|
||||
setIsSettingsBlock(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box
|
||||
@ -41,7 +34,7 @@ export const SettingItemHeader: FC<SettingItemHeaderProps> = ({
|
||||
>
|
||||
{step} этап
|
||||
</Typography>
|
||||
<IconButton onClick={handleClick}>
|
||||
<IconButton onClick={setStep}>
|
||||
<EditPencil
|
||||
color={theme.palette.brightPurple.main}
|
||||
width={"18px"}
|
||||
|
||||
@ -0,0 +1,92 @@
|
||||
import { FC } from "react";
|
||||
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { StepButtonsBlock } from "../StepButtonsBlock";
|
||||
import { SettingItem } from "./SettingItem/SettingItem";
|
||||
import { SelectedQuestions, SelectedTags } from "../types";
|
||||
|
||||
type AmoSettingsBlockProps = {
|
||||
stepTitles: string[];
|
||||
selectedFunnel: string | null;
|
||||
selectedStage: string | null;
|
||||
selectedDealUser: string | null;
|
||||
selectedQuestions: SelectedQuestions;
|
||||
selectedTags: SelectedTags;
|
||||
toBack: () => void
|
||||
setStep: (step: number) => void
|
||||
};
|
||||
|
||||
export const SettingsBlock: FC<AmoSettingsBlockProps> = ({
|
||||
stepTitles,
|
||||
selectedFunnel,
|
||||
selectedDealUser,
|
||||
selectedStage,
|
||||
selectedQuestions,
|
||||
selectedTags,
|
||||
toBack,
|
||||
setStep,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
|
||||
return (
|
||||
<Box sx={{ flexGrow: 1, width: "100%", height: "100%"}}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "24px",
|
||||
fontWeight: 500,
|
||||
lineHeight: "28.44px"
|
||||
|
||||
}}
|
||||
>
|
||||
Мои настройки
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "20px",
|
||||
width: "100%",
|
||||
minHheight: "440px",
|
||||
maxHeight: "90%",
|
||||
borderRadius: "10px",
|
||||
padding: " 0 20px",
|
||||
boxShadow: "0 0 20px rgba(0, 0, 0, 0.15)",
|
||||
overflowY: "auto",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
{stepTitles &&
|
||||
stepTitles.map((title, index) => (
|
||||
<SettingItem
|
||||
step={index+1}
|
||||
title={title}
|
||||
selectedDealUser={selectedDealUser}
|
||||
selectedFunnel={selectedFunnel}
|
||||
selectedStage={selectedStage}
|
||||
selectedQuestions={selectedQuestions}
|
||||
selectedTags={selectedTags}
|
||||
|
||||
setStep={setStep}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
alignSelf: "end",
|
||||
}}
|
||||
>
|
||||
<StepButtonsBlock
|
||||
onSmallBtnClick={toBack}
|
||||
isLargeBtnMissing={true}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@ -30,9 +30,10 @@ export const StepButtonsBlock: FC<StepButtonsBlockProps> = ({
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "end",
|
||||
alignItems: "end",
|
||||
gap: "10px",
|
||||
marginTop: "auto",
|
||||
marginLeft: "auto",
|
||||
mt: "20px"
|
||||
}}
|
||||
>
|
||||
{isSmallBtnMissing || (
|
||||
396
src/pages/IntegrationsPage/IntegrationsModal/Amo/SwitchPages.tsx
Normal file
396
src/pages/IntegrationsPage/IntegrationsModal/Amo/SwitchPages.tsx
Normal file
@ -0,0 +1,396 @@
|
||||
import { useMemo, useState } from "react"
|
||||
import { Dialog, IconButton, Typography, useMediaQuery, useTheme, Box, Skeleton } from "@mui/material";
|
||||
import { useQuestions } from "@/stores/questions/hooks";
|
||||
import { redirect } from "react-router-dom";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
|
||||
import { RemoveAccount } from "./RemoveAccount";
|
||||
import { DeleteTagQuestion } from "./DeleteTagQuestion";
|
||||
import { AmoLogin } from "./AmoLogin";
|
||||
import { Pipelines } from "./Pipelines";
|
||||
import { PipelineSteps } from "./PipelineSteps";
|
||||
import { DealPerformers } from "./DealPerformers";
|
||||
import { AmoTags } from "./Tags/AmoTags";
|
||||
import { AmoQuestions } from "./Questions/AmoQuestions";
|
||||
import { ModalTitle } from "./ModalTitle";
|
||||
import { SettingsBlock } from "./SettingsBlock/SettingsBlock";
|
||||
import { AccountInfo } from "./AccountInfo";
|
||||
import { useAmoIntegration } from "./useAmoIntegration";
|
||||
import { MinifiedData, QuestionKeys, TagKeys, TagQuestionHC } from "./types";
|
||||
import { Quiz } from "@/model/quiz/quiz";
|
||||
import { AccountResponse, setIntegrationRules, updateIntegrationRules } from "@/api/integration";
|
||||
import { AnyTypedQuizQuestion } from "@frontend/squzanswerer";
|
||||
import { UntypedQuizQuestion } from "@/model/questionTypes/shared";
|
||||
|
||||
const FCTranslate = {
|
||||
"name": "имя",
|
||||
"email": "почта",
|
||||
"phone": "телефон",
|
||||
"text": "номер",
|
||||
"address": "адрес",
|
||||
}
|
||||
|
||||
interface Props {
|
||||
quiz: Quiz;
|
||||
questions: (AnyTypedQuizQuestion | UntypedQuizQuestion)[];
|
||||
firstRules: boolean;
|
||||
accountInfo: AccountResponse | null;
|
||||
arrayOfPipelines: MinifiedData[];
|
||||
arrayOfPipelinesSteps: MinifiedData[];
|
||||
arrayOfUsers: MinifiedData[];
|
||||
arrayOfTags: MinifiedData[];
|
||||
arrayOfFields: MinifiedData[];
|
||||
selectedPipeline: string | null;
|
||||
selectedCurrentFields: MinifiedData[];
|
||||
selectedPipelineStep: string | null;
|
||||
selectedDealUser: string | null;
|
||||
setSelectedPipeline: any;
|
||||
setSelectedPipelineStep: any;
|
||||
setSelectedDealPerformer: any;
|
||||
selectedTags: any;
|
||||
setSelectedTags: any;
|
||||
selectedQuestions: any;
|
||||
setSelectedQuestions: any;
|
||||
setPageOfPipelines: () => void;
|
||||
setPageOfPipelinesSteps: () => void;
|
||||
setPageOfUsers: () => void;
|
||||
setPageOfTags: () => void;
|
||||
setPageOfFields: () => void;
|
||||
setSelectedCurrentFields: any;
|
||||
handleCloseModal: any;
|
||||
}
|
||||
|
||||
export const SwitchPages = ({
|
||||
quiz,
|
||||
questions,
|
||||
firstRules,
|
||||
accountInfo,
|
||||
arrayOfPipelines,
|
||||
arrayOfPipelinesSteps,
|
||||
arrayOfUsers,
|
||||
arrayOfTags,
|
||||
arrayOfFields,
|
||||
selectedPipeline,
|
||||
setSelectedPipeline,
|
||||
selectedCurrentFields,
|
||||
selectedPipelineStep,
|
||||
setSelectedPipelineStep,
|
||||
selectedDealUser,
|
||||
setSelectedDealPerformer,
|
||||
selectedTags,
|
||||
setSelectedTags,
|
||||
selectedQuestions,
|
||||
setSelectedQuestions,
|
||||
setPageOfPipelines,
|
||||
setPageOfPipelinesSteps,
|
||||
setPageOfUsers,
|
||||
setPageOfTags,
|
||||
setPageOfFields,
|
||||
setSelectedCurrentFields,
|
||||
handleCloseModal,
|
||||
}: Props) => {
|
||||
const [step, setStep] = useState(0)
|
||||
const [specialPage, setSpecialPage] = useState<"deleteCell" | "removeAccount" | "settingsBlock" | "accountInfo" | "amoLogin" | "">(accountInfo ? "accountInfo" : "amoLogin")
|
||||
const [openDelete, setOpenDelete] = useState<TagQuestionHC | null>(null);
|
||||
|
||||
const startDeleteTagQuestion = (itemForDelete) => {
|
||||
setOpenDelete(itemForDelete)
|
||||
setSpecialPage("deleteCell")
|
||||
}
|
||||
|
||||
const minifiedQuestions = useMemo(
|
||||
() =>
|
||||
questions
|
||||
.filter((q) => q.type !== "result" && q.type !== null)
|
||||
.map(({ backendId, title }) => ({
|
||||
id: backendId.toString() as string,
|
||||
title,
|
||||
})),
|
||||
[questions]
|
||||
);
|
||||
const FieldsAllowedFC = useMemo(
|
||||
() => {
|
||||
const list: MinifiedData[] = []
|
||||
if (quiz.config.showfc) {
|
||||
const fields = quiz.config.formContact.fields
|
||||
for (let key in fields) {
|
||||
if (fields[key].used) list.push({
|
||||
id: key,
|
||||
title: FCTranslate[key],
|
||||
entity: "Contact",
|
||||
})
|
||||
}
|
||||
}
|
||||
return list;
|
||||
},
|
||||
[quiz]
|
||||
);
|
||||
const handleAddTagQuestion = (scope: QuestionKeys | TagKeys, id: string, type: "question" | "tag") => {
|
||||
if (!scope || !id) return;
|
||||
|
||||
if (type === "tag") {
|
||||
setSelectedTags((prevState) => ({
|
||||
...prevState,
|
||||
[scope]: [...prevState[scope as TagKeys], id],
|
||||
}));
|
||||
}
|
||||
|
||||
if (type === "question") {
|
||||
const q = questions.find(e => e.backendId === Number(id))
|
||||
setSelectedQuestions((prevState) => ({
|
||||
...prevState,
|
||||
[scope]: [...prevState[scope as QuestionKeys], {
|
||||
id,
|
||||
title: q?.title || "вопрос",
|
||||
entity: scope,
|
||||
}],
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeleteTagQuestion = () => {
|
||||
if (openDelete === null || !openDelete.scope || !openDelete.id || !openDelete.type) return;
|
||||
if (openDelete.type === "tag") {
|
||||
let newArray = selectedTags[openDelete.scope];
|
||||
const index = newArray.indexOf(openDelete.id);
|
||||
if (index !== -1) newArray.splice(index, 1);
|
||||
|
||||
setSelectedTags((prevState) => ({
|
||||
...prevState,
|
||||
[openDelete.scope]: newArray,
|
||||
}));
|
||||
}
|
||||
|
||||
if (openDelete.type === "question") {
|
||||
let newArray = selectedQuestions
|
||||
newArray[openDelete.scope as QuestionKeys] = newArray[openDelete.scope as QuestionKeys].filter(e => e.id !== openDelete.id)
|
||||
setSelectedQuestions(newArray);
|
||||
setSelectedCurrentFields(selectedCurrentFields.filter(e => e.id !== openDelete.id));
|
||||
|
||||
}
|
||||
setOpenDelete(null);
|
||||
closeSpecialPage();
|
||||
}
|
||||
|
||||
const handleNextStep = () => {
|
||||
setStep((prevState) => prevState + 1);
|
||||
};
|
||||
const handlePrevStep = () => {
|
||||
setStep((prevState) => prevState - 1);
|
||||
};
|
||||
const handleSave = () => {
|
||||
if (quiz?.backendId === undefined) return;
|
||||
if (selectedPipeline === null) return enqueueSnackbar("Выберите воронку");
|
||||
if (selectedPipeline === null) return enqueueSnackbar("Выберите этап воронки");
|
||||
|
||||
const body = {
|
||||
PipelineID: Number(selectedPipeline),
|
||||
StepID: Number(selectedPipelineStep),
|
||||
PerformerID: Number(selectedDealUser),
|
||||
// FieldsRule: questionsBackend,
|
||||
TagsToAdd: selectedTags,
|
||||
};
|
||||
|
||||
const FieldsRule = {
|
||||
Company: { QuestionID: {} },
|
||||
Lead: { QuestionID: {} },
|
||||
Customer: { QuestionID: {} },
|
||||
Contact: {
|
||||
QuestionID: {},
|
||||
ContactRuleMap: {
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
for (let key in FieldsRule) {
|
||||
selectedQuestions[key as QuestionKeys].forEach((data) => {
|
||||
FieldsRule[key as QuestionKeys].QuestionID[data.id] = 0;
|
||||
});
|
||||
}
|
||||
|
||||
selectedCurrentFields.forEach((data) => {
|
||||
if (data.entity === "Contact") {
|
||||
FieldsRule.Contact.ContactRuleMap[data.id] = Number(data.amoId)
|
||||
} else {
|
||||
FieldsRule[data.entity].QuestionID[data.id] = Number(data.amoId) || 0
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
for (let key in body.TagsToAdd) {
|
||||
body.TagsToAdd[key as TagKeys] = body.TagsToAdd[key as TagKeys].map((id) => Number(id));
|
||||
}
|
||||
body.FieldsRule = FieldsRule;
|
||||
|
||||
console.log(body)
|
||||
|
||||
if (firstRules) {
|
||||
setIntegrationRules(quiz.backendId.toString(), body);
|
||||
} else {
|
||||
updateIntegrationRules(quiz.backendId.toString(), body);
|
||||
}
|
||||
|
||||
handleCloseModal();
|
||||
};
|
||||
|
||||
|
||||
const closeSpecialPage = () => setSpecialPage("")
|
||||
|
||||
const steps = [
|
||||
{
|
||||
isSettingsAvailable: true,
|
||||
component: (
|
||||
<Pipelines
|
||||
users={arrayOfUsers}
|
||||
pipelines={arrayOfPipelines}
|
||||
handlePrevStep={() => setSpecialPage("accountInfo")}
|
||||
handleNextStep={handleNextStep}
|
||||
selectedDealUser={selectedDealUser}
|
||||
setSelectedDealPerformer={setSelectedDealPerformer}
|
||||
selectedPipeline={selectedPipeline}
|
||||
setSelectedPipeline={setSelectedPipeline}
|
||||
titleProps={{
|
||||
step: step + 2,
|
||||
title: "Выбор воронки",
|
||||
desc: "На этом этапе вы можете выбрать нужную воронку и ответственного за сделку",
|
||||
toSettings: () => setSpecialPage("settingsBlock")
|
||||
}}
|
||||
onScroll={setPageOfPipelines}
|
||||
onScrollUsers={setPageOfUsers}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
isSettingsAvailable: true,
|
||||
component: (
|
||||
<PipelineSteps
|
||||
users={arrayOfUsers}
|
||||
selectedDealUser={selectedDealUser}
|
||||
selectedStep={selectedPipelineStep}
|
||||
steps={arrayOfPipelinesSteps}
|
||||
setSelectedDealPerformer={setSelectedDealPerformer}
|
||||
setSelectedStep={setSelectedPipelineStep}
|
||||
handlePrevStep={handlePrevStep}
|
||||
handleNextStep={handleNextStep}
|
||||
titleProps={{
|
||||
step: step + 2,
|
||||
title: "Выбор этапа воронки",
|
||||
desc: "На этом этапе вы можете выбрать нужный этап и ответственного за сделку",
|
||||
toSettings: () => setSpecialPage("settingsBlock")
|
||||
}}
|
||||
onScroll={setPageOfPipelinesSteps}
|
||||
onScrollUsers={setPageOfUsers}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
isSettingsAvailable: true,
|
||||
component: (
|
||||
<DealPerformers
|
||||
handlePrevStep={handlePrevStep}
|
||||
handleNextStep={handleNextStep}
|
||||
users={arrayOfUsers}
|
||||
selectedDealUser={selectedDealUser}
|
||||
setSelectedDealPerformer={setSelectedDealPerformer}
|
||||
titleProps={{
|
||||
step: step + 2,
|
||||
title: "Сделка",
|
||||
desc: "На этом этапе вы можете выбрать ответственного за сделку",
|
||||
toSettings: () => setSpecialPage("settingsBlock")
|
||||
}}
|
||||
onScrollUsers={setPageOfUsers}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
isSettingsAvailable: true,
|
||||
component: (
|
||||
<AmoTags
|
||||
tagsItems={arrayOfTags}
|
||||
selectedTags={selectedTags}
|
||||
openDelete={startDeleteTagQuestion}
|
||||
handleAddTag={handleAddTagQuestion}
|
||||
handlePrevStep={handlePrevStep}
|
||||
handleNextStep={handleNextStep}
|
||||
titleProps={{
|
||||
step: step + 2,
|
||||
title: "Добавление тегов",
|
||||
desc: "На этом этапе вы можете добавить теги с результатами",
|
||||
toSettings: () => setSpecialPage("settingsBlock")
|
||||
}}
|
||||
onScroll={setPageOfTags}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
isSettingsAvailable: true,
|
||||
component: (
|
||||
<AmoQuestions
|
||||
setSelectedCurrentFields={setSelectedCurrentFields}
|
||||
fieldsItems={arrayOfFields}
|
||||
selectedCurrentFields={selectedCurrentFields}
|
||||
questionsItems={minifiedQuestions}
|
||||
selectedQuestions={selectedQuestions}
|
||||
openDelete={startDeleteTagQuestion}
|
||||
handleAddQuestion={handleAddTagQuestion}
|
||||
handlePrevStep={handlePrevStep}
|
||||
handleNextStep={handleSave}
|
||||
FieldsAllowedFC={FieldsAllowedFC}
|
||||
titleProps={{
|
||||
step: step + 2,
|
||||
title: "Соотнесение вопросов и сущностей",
|
||||
toSettings: () => setSpecialPage("settingsBlock")
|
||||
}}
|
||||
onScroll={setPageOfFields}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
const stepTitles = steps.map((step) => step.title);
|
||||
|
||||
switch (specialPage) {
|
||||
case "deleteCell":
|
||||
return <DeleteTagQuestion
|
||||
close={closeSpecialPage}
|
||||
deleteItem={handleDeleteTagQuestion}
|
||||
/>
|
||||
case "removeAccount":
|
||||
return <RemoveAccount
|
||||
handleCloseModal={handleCloseModal}
|
||||
stopThisPage={closeSpecialPage}
|
||||
/>
|
||||
case "settingsBlock":
|
||||
return <SettingsBlock
|
||||
stepTitles={stepTitles}
|
||||
selectedDealUser={arrayOfUsers.find((u) => u.id === selectedDealUser)?.title || "не указан"}
|
||||
selectedFunnel={arrayOfPipelines.find((p) => p.id === selectedPipeline)?.title || "нет данных"}
|
||||
selectedStage={
|
||||
arrayOfPipelinesSteps.find((s) => s.id === selectedPipelineStep)?.title || "нет данных"
|
||||
}
|
||||
selectedQuestions={selectedQuestions}
|
||||
selectedTags={selectedTags}
|
||||
toBack={() => closeSpecialPage()}
|
||||
setStep={(step: number) => {
|
||||
closeSpecialPage()
|
||||
setStep(step - 1)
|
||||
}}
|
||||
/>
|
||||
case "amoLogin": return <AmoLogin handleNextStep={handleNextStep} />
|
||||
case "accountInfo": return <AccountInfo
|
||||
handleNextStep={() => closeSpecialPage()}
|
||||
accountInfo={accountInfo}
|
||||
toChangeAccount={() => setSpecialPage("removeAccount")}
|
||||
/>
|
||||
|
||||
|
||||
default: return <Box sx={{
|
||||
flexGrow: 1,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "auto"
|
||||
}}>{steps[step].component}</Box>
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,135 @@
|
||||
import { FC, useState } from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { ItemsSelectionView } from "../Questions/ItemsSelectionView/ItemsSelectionView";
|
||||
import { TagsDetailsView } from "./TagsDetailsView/TagsDetailsView";
|
||||
import { MinifiedData, QuestionKeys, SelectedTags, TagKeys, TagQuestionHC } from "../types";
|
||||
import { DataConstrictor } from "../Components/DataConstrictor";
|
||||
import { ModalTitle } from "../ModalTitle";
|
||||
import { StepButtonsBlock } from "../StepButtonsBlock";
|
||||
|
||||
type Props = {
|
||||
tagsItems: MinifiedData[] | [];
|
||||
selectedTags: SelectedTags;
|
||||
handleAddTag: (scope: QuestionKeys | TagKeys, id: string, type: "question" | "tag") => void;
|
||||
openDelete: (data: TagQuestionHC) => void;
|
||||
handlePrevStep: () => void;
|
||||
handleNextStep: () => void;
|
||||
titleProps: {
|
||||
step: number;
|
||||
title: string;
|
||||
desc: string;
|
||||
toSettings: () => void;
|
||||
}
|
||||
onScroll: () => void;
|
||||
|
||||
};
|
||||
|
||||
export const AmoTags: FC<Props> = ({
|
||||
tagsItems,
|
||||
selectedTags,
|
||||
handleAddTag,
|
||||
openDelete,
|
||||
handlePrevStep,
|
||||
handleNextStep,
|
||||
onScroll,
|
||||
titleProps,
|
||||
}) => {
|
||||
const [sortedTagsItems, setSortedTagsItems] = useState<MinifiedData[] | []>(tagsItems);
|
||||
|
||||
const [isSelection, setIsSelection] = useState<boolean>(false);
|
||||
const [activeScope, setActiveScope] = useState<TagKeys | null>(null);
|
||||
const [selectedTag, setSelectedTag] = useState<string | null>(null);
|
||||
|
||||
const handleAdd = () => {
|
||||
if (activeScope === null || selectedTag === null) return;
|
||||
setActiveScope(null);
|
||||
handleAddTag(activeScope, selectedTag, "tag");
|
||||
};
|
||||
const handleDelete = (id: string, scope: TagKeys) => {
|
||||
openDelete({
|
||||
id,
|
||||
scope,
|
||||
type: "tag",
|
||||
});
|
||||
};
|
||||
const startConstrictor = (substr: string) => {
|
||||
const a = tagsItems.filter((mData) => mData.title.toLowerCase().startsWith(substr.toLowerCase()))
|
||||
setSortedTagsItems(a);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
height: "calc( 100% - 70px )",
|
||||
overflow: "auto"
|
||||
}}
|
||||
>
|
||||
<ModalTitle
|
||||
{...titleProps}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
{isSelection && activeScope !== null ? (
|
||||
// Здесь выбираем элемент в табличку
|
||||
<>
|
||||
<DataConstrictor
|
||||
isError={sortedTagsItems.length === 0}
|
||||
constrictor={startConstrictor}
|
||||
/>
|
||||
<ItemsSeactiveScopelectionView
|
||||
items={sortedTagsItems}
|
||||
selectedItemId={selectedTag}
|
||||
setSelectedItem={setSelectedTag}
|
||||
handleScroll={onScroll}
|
||||
activeScope={activeScope}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
// Табличка
|
||||
<TagsDetailsView
|
||||
items={tagsItems}
|
||||
setActiveScope={setActiveScope}
|
||||
selectedTags={selectedTags}
|
||||
setIsSelection={setIsSelection}
|
||||
deleteHC={handleDelete}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
alignSelf: "end",
|
||||
}}
|
||||
>
|
||||
|
||||
{
|
||||
isSelection && activeScope !== null ?
|
||||
<StepButtonsBlock
|
||||
onLargeBtnClick={() => {
|
||||
handleAdd();
|
||||
setActiveScope(null);
|
||||
setIsSelection(false);
|
||||
}}
|
||||
largeBtnText={"Добавить"}
|
||||
onSmallBtnClick={() => {
|
||||
setActiveScope(null);
|
||||
setIsSelection(false);
|
||||
}}
|
||||
smallBtnText={"Отменить"}
|
||||
/>
|
||||
:
|
||||
<StepButtonsBlock
|
||||
onSmallBtnClick={handlePrevStep}
|
||||
onLargeBtnClick={handleNextStep}
|
||||
/>
|
||||
}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -1,14 +1,12 @@
|
||||
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock";
|
||||
import { StepButtonsBlock } from "../../StepButtonsBlock";
|
||||
import { FC } from "react";
|
||||
import { Item } from "../../AmoQuestions/Item/Item";
|
||||
import { Item } from "../../Questions/Item/Item";
|
||||
import { MinifiedData, SelectedTags, TagKeys } from "../../types";
|
||||
|
||||
type TagsDetailsViewProps = {
|
||||
items: MinifiedData[];
|
||||
setIsSelection: (value: boolean) => void;
|
||||
handlePrevStep: () => void;
|
||||
handleNextStep: () => void;
|
||||
setActiveScope: (value: TagKeys | null) => void;
|
||||
selectedTags: SelectedTags;
|
||||
deleteHC: (id: string, scope: TagKeys) => void;
|
||||
@ -19,8 +17,6 @@ export const TagsDetailsView: FC<TagsDetailsViewProps> = ({
|
||||
setActiveScope,
|
||||
selectedTags,
|
||||
setIsSelection,
|
||||
handlePrevStep,
|
||||
handleNextStep,
|
||||
deleteHC,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
@ -30,7 +26,7 @@ export const TagsDetailsView: FC<TagsDetailsViewProps> = ({
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "20px",
|
||||
marginTop: "15px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
@ -41,7 +37,7 @@ export const TagsDetailsView: FC<TagsDetailsViewProps> = ({
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "400px",
|
||||
maxHeight: "380px",
|
||||
flexGrow: 1,
|
||||
borderRadius: "10px",
|
||||
padding: "10px",
|
||||
@ -88,17 +84,6 @@ export const TagsDetailsView: FC<TagsDetailsViewProps> = ({
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "20px",
|
||||
alignSelf: "end",
|
||||
}}
|
||||
>
|
||||
<StepButtonsBlock
|
||||
onSmallBtnClick={handlePrevStep}
|
||||
onLargeBtnClick={handleNextStep}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
172
src/pages/IntegrationsPage/IntegrationsModal/Amo/index.tsx
Normal file
172
src/pages/IntegrationsPage/IntegrationsModal/Amo/index.tsx
Normal file
@ -0,0 +1,172 @@
|
||||
import { FC, useState } from "react";
|
||||
import { Dialog, IconButton, Typography, useMediaQuery, useTheme, Box, Skeleton } from "@mui/material";
|
||||
import { useQuestions } from "@/stores/questions/hooks";
|
||||
import { redirect, useNavigate } from "react-router-dom";
|
||||
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
|
||||
import { useAmoIntegration } from "./useAmoIntegration";
|
||||
import { MinifiedData } from "./types";
|
||||
import { Quiz } from "@/model/quiz/quiz";
|
||||
import { SwitchPages } from "./SwitchPages";
|
||||
|
||||
type IntegrationsModalProps = {
|
||||
isModalOpen: boolean;
|
||||
handleCloseModal: () => void;
|
||||
companyName: string | null;
|
||||
quiz: Quiz;
|
||||
};
|
||||
|
||||
export const AmoCRMModal: FC<IntegrationsModalProps> = ({ isModalOpen, handleCloseModal, companyName, quiz }) => {
|
||||
//Если нет контекста квиза, то и делать на этой страничке нечего
|
||||
if (quiz.backendId === undefined) {
|
||||
redirect("/list");
|
||||
return null;
|
||||
}
|
||||
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||
|
||||
const { questions } = useQuestions();
|
||||
|
||||
const [isTryRemoveAccount, setIsTryRemoveAccount] = useState<boolean>(false);
|
||||
|
||||
const {
|
||||
isLoadingPage,
|
||||
firstRules,
|
||||
accountInfo,
|
||||
arrayOfPipelines,
|
||||
arrayOfPipelinesSteps,
|
||||
arrayOfUsers,
|
||||
arrayOfTags,
|
||||
arrayOfFields,
|
||||
selectedPipeline,
|
||||
setSelectedPipeline,
|
||||
selectedCurrentFields,
|
||||
selectedPipelineStep,
|
||||
setSelectedPipelineStep,
|
||||
selectedDealUser,
|
||||
setSelectedDealPerformer,
|
||||
questionsBackend,
|
||||
selectedTags,
|
||||
setSelectedTags,
|
||||
selectedQuestions,
|
||||
setSelectedQuestions,
|
||||
setPageOfPipelines,
|
||||
setPageOfPipelinesSteps,
|
||||
setPageOfUsers,
|
||||
setPageOfTags,
|
||||
setPageOfFields,
|
||||
setSelectedCurrentFields,
|
||||
} = useAmoIntegration({
|
||||
quizID: quiz.backendId,
|
||||
isModalOpen,
|
||||
isTryRemoveAccount,
|
||||
questions,
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isModalOpen}
|
||||
onClose={handleCloseModal}
|
||||
fullWidth
|
||||
// fullScreen={isMobile}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
maxWidth: isTablet ? "100%" : "919px",
|
||||
height: "658px",
|
||||
borderRadius: "12px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "68px",
|
||||
backgroundColor: theme.palette.background.default,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: isMobile ? "20px" : "24px",
|
||||
fontWeight: "500",
|
||||
padding: "20px",
|
||||
color: theme.palette.grey2.main,
|
||||
}}
|
||||
>
|
||||
Интеграция с {companyName ? companyName : "партнером"}
|
||||
</Typography>
|
||||
</Box>
|
||||
<IconButton
|
||||
onClick={handleCloseModal}
|
||||
sx={{
|
||||
width: "12px",
|
||||
height: "12px",
|
||||
position: "absolute",
|
||||
right: "15px",
|
||||
top: "15px",
|
||||
}}
|
||||
>
|
||||
<CloseIcon sx={{ width: "12px", height: "12px", transform: "scale(1.5)" }} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
<Box
|
||||
className="родитель"
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
padding: "15px 20px 15px",
|
||||
flexGrow: 1,
|
||||
height: "100%",
|
||||
overflow: "auto"
|
||||
}}
|
||||
>
|
||||
{isLoadingPage ?
|
||||
<Skeleton
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
transform: "none",
|
||||
}}
|
||||
/> :
|
||||
<SwitchPages
|
||||
quiz={quiz}
|
||||
questions={questions}
|
||||
firstRules={firstRules}
|
||||
accountInfo={accountInfo}
|
||||
arrayOfPipelines={arrayOfPipelines}
|
||||
arrayOfPipelinesSteps={arrayOfPipelinesSteps}
|
||||
arrayOfUsers={arrayOfUsers}
|
||||
arrayOfTags={arrayOfTags}
|
||||
arrayOfFields={arrayOfFields}
|
||||
selectedPipeline={selectedPipeline}
|
||||
setSelectedPipeline={setSelectedPipeline}
|
||||
selectedCurrentFields={selectedCurrentFields}
|
||||
selectedPipelineStep={selectedPipelineStep}
|
||||
setSelectedPipelineStep={setSelectedPipelineStep}
|
||||
selectedDealUser={selectedDealUser}
|
||||
setSelectedDealPerformer={setSelectedDealPerformer}
|
||||
selectedTags={selectedTags}
|
||||
setSelectedTags={setSelectedTags}
|
||||
selectedQuestions={selectedQuestions}
|
||||
setSelectedQuestions={setSelectedQuestions}
|
||||
setPageOfPipelines={setPageOfPipelines}
|
||||
setPageOfPipelinesSteps={setPageOfPipelinesSteps}
|
||||
setPageOfUsers={setPageOfUsers}
|
||||
setPageOfTags={setPageOfTags}
|
||||
setPageOfFields={setPageOfFields}
|
||||
setSelectedCurrentFields={setSelectedCurrentFields}
|
||||
handleCloseModal={handleCloseModal}
|
||||
/>
|
||||
}
|
||||
</Box>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export const diffArr = (arr_A: MinifiedData[], arr_B: MinifiedData[]) => {
|
||||
return arr_A.filter(person_A => !arr_B.some(person_B => person_A.id === person_B.id));
|
||||
}
|
||||
@ -13,14 +13,15 @@ import {
|
||||
getFields,
|
||||
} from "@/api/integration";
|
||||
import { AnyTypedQuizQuestion } from "@frontend/squzanswerer";
|
||||
import { UntypedQuizQuestion } from "@/model/questionTypes/shared";
|
||||
|
||||
const SIZE = 275;
|
||||
const SIZE = 25;
|
||||
|
||||
interface Props {
|
||||
isModalOpen: boolean;
|
||||
isTryRemoveAccount: boolean;
|
||||
quizID: number;
|
||||
questions: AnyTypedQuizQuestion[]
|
||||
questions: (AnyTypedQuizQuestion | UntypedQuizQuestion)[]
|
||||
}
|
||||
|
||||
const FCTranslate = {
|
||||
@ -30,6 +31,13 @@ const FCTranslate = {
|
||||
"text": "номер",
|
||||
"address": "адрес",
|
||||
}
|
||||
|
||||
let isReadyGetPipeline = true;
|
||||
let isReadyGetPipelineStep = true;
|
||||
let isReadyGetUsers = true;
|
||||
let isReadyGetTags = true;
|
||||
let isReadyGetFields = true;
|
||||
|
||||
export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, questions }: Props) => {
|
||||
const [isLoadingPage, setIsLoadingPage] = useState<boolean>(true);
|
||||
const [firstRules, setFirstRules] = useState<boolean>(false);
|
||||
@ -101,15 +109,15 @@ export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, que
|
||||
|
||||
if (gottenList !== null) {
|
||||
Object.keys(gottenList.QuestionID).forEach((qId) => {
|
||||
const q = questions.find(e=>e.backendId === Number(qId)) || {}
|
||||
const q = questions.find(e => e.backendId === Number(qId)) || {}
|
||||
gottenQuestions[key as QuestionKeys].push({
|
||||
id: qId,
|
||||
title: q.title,
|
||||
entity: key,
|
||||
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (key === "Contact") {
|
||||
@ -153,8 +161,8 @@ export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, que
|
||||
|
||||
useEffect(() => {
|
||||
const transletedQuestions = {}
|
||||
|
||||
Object.keys(selectedQuestions).forEach((column) => {
|
||||
|
||||
Object.keys(selectedQuestions)?.forEach((column) => {
|
||||
selectedQuestions[column].forEach((minifiedData) => {
|
||||
const q = questions.find(e => e.backendId === Number(minifiedData.id)) || {}
|
||||
transletedQuestions[column] = {
|
||||
@ -168,115 +176,142 @@ export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, que
|
||||
}, [questions])
|
||||
|
||||
useEffect(() => {
|
||||
getPipelines({
|
||||
page: pageOfPipelines,
|
||||
size: SIZE,
|
||||
}).then(([response]) => {
|
||||
if (response && response.items !== null) {
|
||||
const minifiedPipelines: MinifiedData[] = [];
|
||||
|
||||
response.items.forEach((step) => {
|
||||
minifiedPipelines.push({
|
||||
id: step.AmoID.toString(),
|
||||
title: step.Name,
|
||||
});
|
||||
});
|
||||
setArrayOfPipelines((prevItems) => [...prevItems, ...minifiedPipelines]);
|
||||
setPageOfPipelinesSteps(1);
|
||||
}
|
||||
});
|
||||
}, [pageOfPipelines]);
|
||||
useEffect(() => {
|
||||
const oldData = pageOfPipelinesSteps === 1 ? [] : arrayOfPipelinesSteps;
|
||||
if (selectedPipeline !== null)
|
||||
getSteps({
|
||||
page: pageOfPipelinesSteps,
|
||||
if (isReadyGetPipeline) {
|
||||
getPipelines({
|
||||
page: pageOfPipelines,
|
||||
size: SIZE,
|
||||
pipelineId: Number(selectedPipeline),
|
||||
}).then(([response]) => {
|
||||
if (response && response.items !== null) {
|
||||
const minifiedSteps: MinifiedData[] = [];
|
||||
const minifiedPipelines: MinifiedData[] = [];
|
||||
|
||||
response.items.forEach((step) => {
|
||||
minifiedSteps.push({
|
||||
minifiedPipelines.push({
|
||||
id: step.AmoID.toString(),
|
||||
title: step.Name,
|
||||
});
|
||||
});
|
||||
setArrayOfPipelinesSteps([...oldData, ...minifiedSteps]);
|
||||
setArrayOfPipelines((prevItems) => [...prevItems, ...minifiedPipelines]);
|
||||
setPageOfPipelinesSteps(1);
|
||||
} else {
|
||||
isReadyGetPipeline = false
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [pageOfPipelines]);
|
||||
useEffect(() => {
|
||||
if (isReadyGetPipelineStep) {
|
||||
const oldData = pageOfPipelinesSteps === 1 ? [] : arrayOfPipelinesSteps;
|
||||
if (selectedPipeline !== null)
|
||||
getSteps({
|
||||
page: pageOfPipelinesSteps,
|
||||
size: SIZE,
|
||||
pipelineId: Number(selectedPipeline),
|
||||
}).then(([response]) => {
|
||||
if (response && response.items !== null) {
|
||||
const minifiedSteps: MinifiedData[] = [];
|
||||
|
||||
response.items.forEach((step) => {
|
||||
minifiedSteps.push({
|
||||
id: step.AmoID.toString(),
|
||||
title: step.Name,
|
||||
});
|
||||
});
|
||||
setArrayOfPipelinesSteps([...oldData, ...minifiedSteps]);
|
||||
} else {
|
||||
isReadyGetPipelineStep = false
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [selectedPipeline, pageOfPipelinesSteps]);
|
||||
useEffect(() => {
|
||||
getUsers({
|
||||
page: pageOfUsers,
|
||||
size: SIZE,
|
||||
}).then(([response]) => {
|
||||
if (response && response.items !== null) {
|
||||
const minifiedUsers: MinifiedData[] = [];
|
||||
if (isReadyGetUsers) {
|
||||
getUsers({
|
||||
page: pageOfUsers,
|
||||
size: SIZE,
|
||||
}).then(([response]) => {
|
||||
if (response && response.items !== null) {
|
||||
const minifiedUsers: MinifiedData[] = [];
|
||||
|
||||
response.items.forEach((step) => {
|
||||
minifiedUsers.push({
|
||||
id: step.amoUserID.toString(),
|
||||
title: step.name,
|
||||
response.items.forEach((step) => {
|
||||
minifiedUsers.push({
|
||||
id: step.amoUserID.toString(),
|
||||
title: step.name,
|
||||
});
|
||||
});
|
||||
});
|
||||
setArrayOfUsers((prevItems) => [...prevItems, ...minifiedUsers]);
|
||||
}
|
||||
});
|
||||
setArrayOfUsers((prevItems) => [...prevItems, ...minifiedUsers]);
|
||||
} else {
|
||||
isReadyGetUsers = false
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [pageOfUsers]);
|
||||
useEffect(() => {
|
||||
getTags({
|
||||
page: pageOfTags,
|
||||
size: SIZE,
|
||||
}).then(([response]) => {
|
||||
if (response && response.items !== null) {
|
||||
const minifiedTags: MinifiedData[] = [];
|
||||
if (isReadyGetTags) {
|
||||
getTags({
|
||||
page: pageOfTags,
|
||||
size: SIZE,
|
||||
}).then(([response]) => {
|
||||
if (response && response.items !== null) {
|
||||
const minifiedTags: MinifiedData[] = [];
|
||||
|
||||
response.items.forEach((step) => {
|
||||
minifiedTags.push({
|
||||
id: step.AmoID.toString(),
|
||||
title: step.Name,
|
||||
entity:
|
||||
step.Entity === "leads"
|
||||
? "Lead"
|
||||
: step.Entity === "contacts"
|
||||
? "Contact"
|
||||
: step.Entity === "companies"
|
||||
? "Company"
|
||||
: "Customer",
|
||||
response.items.forEach((step) => {
|
||||
minifiedTags.push({
|
||||
id: step.AmoID.toString(),
|
||||
title: step.Name,
|
||||
entity:
|
||||
step.Entity === "leads"
|
||||
? "Lead"
|
||||
: step.Entity === "contacts"
|
||||
? "Contact"
|
||||
: step.Entity === "companies"
|
||||
? "Company"
|
||||
: "Customer",
|
||||
});
|
||||
});
|
||||
});
|
||||
setArrayOfTags((prevItems) => [...prevItems, ...minifiedTags]);
|
||||
}
|
||||
});
|
||||
setArrayOfTags((prevItems) => [...prevItems, ...minifiedTags]);
|
||||
} else {
|
||||
isReadyGetTags = false
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [pageOfTags]);
|
||||
useEffect(() => {
|
||||
getFields({
|
||||
page: pageOfTags,
|
||||
size: SIZE,
|
||||
}).then(([response]) => {
|
||||
if (response && response.items !== null) {
|
||||
const minifiedTags: MinifiedData[] = [];
|
||||
if (isReadyGetFields) {
|
||||
getFields({
|
||||
page: pageOfTags,
|
||||
size: SIZE,
|
||||
}).then(([response]) => {
|
||||
if (response && response.items !== null) {
|
||||
const minifiedTags: MinifiedData[] = [];
|
||||
|
||||
response.items.forEach((field) => {
|
||||
minifiedTags.push({
|
||||
id: field.AmoID.toString(),
|
||||
title: field.Name,
|
||||
entity:
|
||||
field.Entity === "leads"
|
||||
? "Lead"
|
||||
: field.Entity === "contacts"
|
||||
? "Contact"
|
||||
: field.Entity === "companies"
|
||||
? "Company"
|
||||
: "Customer",
|
||||
response.items.forEach((field) => {
|
||||
minifiedTags.push({
|
||||
id: field.AmoID.toString(),
|
||||
title: field.Name,
|
||||
entity:
|
||||
field.Entity === "leads"
|
||||
? "Lead"
|
||||
: field.Entity === "contacts"
|
||||
? "Contact"
|
||||
: field.Entity === "companies"
|
||||
? "Company"
|
||||
: "Customer",
|
||||
});
|
||||
});
|
||||
});
|
||||
setArrayOfFields((prevItems) => [...prevItems, ...minifiedTags]);
|
||||
}
|
||||
});
|
||||
setArrayOfFields((prevItems) => [...prevItems, ...minifiedTags]);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
isReadyGetFields = false
|
||||
}
|
||||
}, [pageOfFields]);
|
||||
useEffect(() => () => {
|
||||
isReadyGetPipeline = true;
|
||||
isReadyGetPipelineStep = true;
|
||||
isReadyGetUsers = true;
|
||||
isReadyGetTags = true;
|
||||
isReadyGetFields = true;
|
||||
}, [])
|
||||
|
||||
return {
|
||||
isLoadingPage,
|
||||
@ -299,10 +334,11 @@ export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, que
|
||||
setSelectedTags,
|
||||
selectedQuestions,
|
||||
setSelectedQuestions,
|
||||
setPageOfPipelines,
|
||||
setPageOfPipelinesSteps,
|
||||
setPageOfUsers,
|
||||
setPageOfTags,
|
||||
setPageOfPipelines: () => setPageOfPipelines(old => old + 1),
|
||||
setPageOfPipelinesSteps: () => setPageOfPipelinesSteps(old => old + 1),
|
||||
setPageOfUsers: () => setPageOfUsers(old => old + 1),
|
||||
setPageOfTags: () => setPageOfTags(old => old + 1),
|
||||
setPageOfFields: () => setPageOfFields(old => old + 1),
|
||||
setSelectedCurrentFields,
|
||||
};
|
||||
};
|
||||
|
||||
@ -16,7 +16,7 @@ const AnalyticsModal = lazy(() =>
|
||||
);
|
||||
|
||||
const AmoCRMModal = lazy(() =>
|
||||
import("../IntegrationsModal/Amo/AmoCRMModal").then((module) => ({
|
||||
import("../IntegrationsModal/Amo").then((module) => ({
|
||||
default: module.AmoCRMModal,
|
||||
}))
|
||||
);
|
||||
|
||||
10
src/utils/throttle.ts
Normal file
10
src/utils/throttle.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export function determineScrollBottom(e: any, callback: any) {
|
||||
const scrollHeight = e.target.scrollHeight;
|
||||
const scrollTop = e.target.scrollTop;
|
||||
const clientHeight = e.target.clientHeight;
|
||||
const scrolledToBottom = scrollTop / (scrollHeight - clientHeight) >= 0.9;
|
||||
|
||||
if (scrolledToBottom) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
@ -1513,10 +1513,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.2.tgz#d8bae93ac8b815b2bd7a98078cf91e2724ef11e5"
|
||||
integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==
|
||||
|
||||
"@frontend/kitui@^1.0.84":
|
||||
version "1.0.84"
|
||||
resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/21/packages/npm/@frontend/kitui/-/@frontend/kitui-1.0.84.tgz#9b655b776433fb8ea6d0840897d941e66530df7f"
|
||||
integrity sha1-m2Vbd2Qz+46m0IQIl9lB5mUw338=
|
||||
"@frontend/kitui@^1.0.85":
|
||||
version "1.0.85"
|
||||
resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/21/packages/npm/@frontend/kitui/-/@frontend/kitui-1.0.85.tgz#1a384c9ff3314175c1ba3d35d0979da7026a21ab"
|
||||
integrity sha1-GjhMn/MxQXXBuj010JedpwJqIas=
|
||||
dependencies:
|
||||
immer "^10.0.2"
|
||||
reconnecting-eventsource "^1.6.2"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user