изменены передаваемые типы в компоненты амо модалки

This commit is contained in:
Nastya 2024-06-15 08:00:58 +03:00
parent 4354d54346
commit dcb254e8e4
16 changed files with 602 additions and 704 deletions

@ -20,11 +20,6 @@ export type AccountResponse = {
subdomain: string; subdomain: string;
country: string; country: string;
driveURL: string; driveURL: string;
// AmoUiserid: number;
// Email: string;
// Role: string;
// Group: number;
// AmoUserID: number;
}; };
export const getAccount = async (): Promise< export const getAccount = async (): Promise<

@ -1,172 +1,61 @@
import * as React from "react"; import * as React from "react";
import { FC, useEffect, useMemo, useRef, useState } from "react"; import { FC, useMemo } from "react";
import Radio from "@mui/material/Radio";
import RadioGroup from "@mui/material/RadioGroup";
import FormControlLabel from "@mui/material/FormControlLabel";
import Box from "@mui/material/Box";
import CheckboxIcon from "@icons/Checkbox"; import CheckboxIcon from "@icons/Checkbox";
import { Typography, useMediaQuery, useTheme } from "@mui/material";
import { import {
getPipelines, SelectChangeEvent,
getSteps, Typography,
getTags, useTheme,
PaginationRequest, Box,
Pipeline, FormControlLabel,
Step, RadioGroup,
Tag, Radio,
} from "@api/integration"; } from "@mui/material";
import type { TagQuestionObject } from "@/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal"
type Items = {
id: string;
title: string;
subTitle?: string;
}
type CustomRadioGroupProps = { type CustomRadioGroupProps = {
type?: string; items: Items[] | [];
selectedValue: string | null; selectedItemId?: string | null;
setSelectedValue: (value: string | null) => void; setSelectedItem: (value: string | null) => void;
pipelineId?: number | null; handleScroll: () => void;
items: TagQuestionObject[]
tags: Tag[]
setTags?: (setValueFunc: (value: Tag[]) => Tag[]) => void;
}; };
const SIZE = 25;
export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
type,
selectedValue,
setSelectedValue,
pipelineId,
items, items,
tags = [], selectedItemId = "",
setTags, setSelectedItem,
handleScroll,
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(500)); const currentItem = useMemo(() => {
if (selectedItemId !== null && selectedItemId.length > 0) {
return items.find(item => item.id === selectedItemId) || null
}
return null;
}, [selectedItemId, items])
const [currentValue, setCurrentValue] = useState<string | null>( const onScroll = React.useCallback((e: React.UIEvent<HTMLDivElement>) => {
selectedValue,
);
const [page, setPage] = useState(1);
const [isLoading, setIsLoading] = useState(false);
const [steps, setSteps] = useState<Step[]>([]);
const [pipelines, setPipelines] = useState<Pipeline[]>([]);
const [hasMoreItems, setHasMoreItems] = useState(true);
const boxRef = useRef(null);
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSelectedValue((event.target as HTMLInputElement).value);
setCurrentValue((event.target as HTMLInputElement).value);
};
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
const scrollHeight = e.currentTarget.scrollHeight; const scrollHeight = e.currentTarget.scrollHeight;
const scrollTop = e.currentTarget.scrollTop; const scrollTop = e.currentTarget.scrollTop;
const clientHeight = e.currentTarget.clientHeight; const clientHeight = e.currentTarget.clientHeight;
const scrolledToBottom = scrollTop / (scrollHeight - clientHeight) > 0.9; const scrolledToBottom = scrollTop / (scrollHeight - clientHeight) > 0.9;
if (scrolledToBottom && !isLoading && hasMoreItems) { if (scrolledToBottom) {
setPage((prevPage) => prevPage + 1); handleScroll();
} }
}; }, []);
useEffect(() => {
if (type === "typeTags" && hasMoreItems && setTags !== undefined) {
setIsLoading(true);
const pagination: PaginationRequest = {
page: page,
size: SIZE,
};
getTags(pagination).then(([response]) => {
if (response && response.items !== null) {
setTags((prevItems:Tag[]) => [...prevItems, ...response.items]);
if (response.items.length < SIZE) {
setHasMoreItems(false);
}
}
setIsLoading(false);
});
}
if (type === "typeSteps" && hasMoreItems && pipelineId) {
setIsLoading(true);
const pagination: PaginationRequest & { pipelineId: number } = {
page: page,
size: SIZE,
pipelineId: pipelineId,
};
getSteps(pagination).then(([response]) => {
if (response && response.items !== null) {
setSteps((prevItems) => [...prevItems, ...response.items]);
if (response.items.length < SIZE) {
setHasMoreItems(false);
}
}
setIsLoading(false);
});
}
if (type === "typePipelines" && hasMoreItems) {
setIsLoading(true);
const pagination: PaginationRequest = {
page: page,
size: SIZE,
};
getPipelines(pagination).then(([response]) => {
if (response && response.items !== null) {
setPipelines((prevItems) => [...prevItems, ...response.items]);
if (response.items.length < SIZE) {
setHasMoreItems(false);
}
}
setIsLoading(false);
});
}
}, [page, type, hasMoreItems, pipelineId]);
const formControlLabels = useMemo(() => { const formControlLabels = useMemo(() => {
if (type === "typeTags" && tags && tags.length !== 0) { if (items.length !== 0) {
return tags.map((item) => ( return items.map( item =>
<FormControlLabel <FormControlLabel
key={item.AmoID} key={item.id}
sx={{
padding: "15px",
borderBottom: `1px solid ${theme.palette.background.default}`,
display: "flex",
justifyContent: "space-between",
borderRadius: "12px",
margin: 0,
backgroundColor:
currentValue === Number(item.AmoID)
? theme.palette.background.default
: theme.palette.common.white,
}}
value={Number(item.AmoID)}
control={
<Radio
checkedIcon={
<CheckboxIcon
checked
isRounded
color={theme.palette.brightPurple.main}
/>
}
icon={<CheckboxIcon isRounded />}
/>
}
label={
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography sx={{ color: `${item.Color}` }}>
{item.Name}
</Typography>
<Typography>{item.Entity}</Typography>
</Box>
}
labelPlacement={"start"}
/>
));
}
if (type === "typeSteps" && steps && steps.length !== 0) {
return steps.map((step) => (
<FormControlLabel
key={step.ID}
sx={{ sx={{
color: "black", color: "black",
padding: "15px", padding: "15px",
@ -176,11 +65,11 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
borderRadius: "12px", borderRadius: "12px",
margin: 0, margin: 0,
backgroundColor: backgroundColor:
currentValue === step.Name currentItem?.id === item.id
? theme.palette.background.default ? theme.palette.background.default
: theme.palette.common.white, : theme.palette.common.white,
}} }}
value={step.AmoID} value={item.id}
control={ control={
<Radio <Radio
checkedIcon={ checkedIcon={
@ -193,90 +82,10 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
icon={<CheckboxIcon isRounded />} icon={<CheckboxIcon isRounded />}
/> />
} }
label={step.Name} label={item.title}
labelPlacement={"start"} labelPlacement={"start"}
/> />
)); )
}
if (type === "typePipelines" && pipelines && pipelines.length !== 0) {
return pipelines.map((pipeline) => (
<FormControlLabel
key={pipeline.ID}
sx={{
color: "black",
padding: "15px",
borderBottom: `1px solid ${theme.palette.background.default}`,
display: "flex",
justifyContent: "space-between",
borderRadius: "12px",
margin: 0,
backgroundColor:
currentValue === pipeline.Name
? theme.palette.background.default
: theme.palette.common.white,
"&.MuiFormControlLabel-root > .MuiTypography-root": {
width: "200px",
overflow: "hidden",
textOverflow: "ellipsis"
}
}}
value={pipeline.AmoID}
control={
<Radio
checkedIcon={
<CheckboxIcon
checked
isRounded
color={theme.palette.brightPurple.main}
/>
}
icon={<CheckboxIcon isRounded />}
/>
}
label={pipeline.Name}
labelPlacement={"start"}
/>
));
}
if (type === "typeQuestions" && items && items.length !== 0) {
return items.map(({ backendId, title }) => (
<FormControlLabel
key={backendId}
sx={{
color: "black",
padding: "15px",
borderBottom: `1px solid ${theme.palette.background.default}`,
display: "flex",
justifyContent: "space-between",
borderRadius: "12px",
margin: 0,
backgroundColor:
currentValue === Number(backendId)
? theme.palette.background.default
: theme.palette.common.white,
"&.MuiFormControlLabel-root > .MuiTypography-root": {
width: "200px",
overflow: "hidden",
textOverflow: "ellipsis"
}
}}
value={Number(backendId)}
control={
<Radio
checkedIcon={
<CheckboxIcon
checked
isRounded
color={theme.palette.brightPurple.main}
/>
}
icon={<CheckboxIcon isRounded />}
/>
}
label={title}
labelPlacement={"start"}
/>
));
} }
return ( return (
<Box <Box
@ -291,11 +100,10 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
<Typography>Нет элементов</Typography> <Typography>Нет элементов</Typography>
</Box> </Box>
); );
}, [tags, steps, currentValue, type, pipelines]); }, [items]);
return ( return (
<Box <Box
ref={boxRef}
onScroll={handleScroll} onScroll={handleScroll}
sx={{ sx={{
border: `1px solid ${theme.palette.grey2.main}`, border: `1px solid ${theme.palette.grey2.main}`,
@ -308,10 +116,9 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
<RadioGroup <RadioGroup
aria-labelledby="demo-controlled-radio-buttons-group" aria-labelledby="demo-controlled-radio-buttons-group"
name="controlled-radio-buttons-group" name="controlled-radio-buttons-group"
value={currentValue} value={setSelectedItem}
onChange={(e) => { onChange={({ target }: SelectChangeEvent<string>) => setSelectedItem(target.value)}
handleChange(e) onScroll={onScroll}
}}
> >
{formControlLabels} {formControlLabels}
</RadioGroup> </RadioGroup>

@ -1,3 +1,6 @@
import * as React from "react";
import { FC, useCallback, useMemo, useRef, useState } from "react";
import { import {
Avatar, Avatar,
MenuItem, MenuItem,
@ -6,96 +9,64 @@ import {
Typography, Typography,
useMediaQuery, useMediaQuery,
useTheme, useTheme,
Box,
} from "@mui/material"; } from "@mui/material";
import Box from "@mui/material/Box";
import * as React from "react";
import { FC, useCallback, useEffect, useMemo, useRef, useState } from "react";
import "./CustomSelect.css"; import "./CustomSelect.css";
import arrow_down from "../../assets/icons/arrow_down.svg"; import arrow_down from "../../assets/icons/arrow_down.svg";
import { getUsers, PaginationRequest, User } from "@api/integration";
type Items = {
id: string;
title: string;
subTitle: string;
}
type CustomSelectProps = { type CustomSelectProps = {
selectedItem: string | null; items: Items[] | [];
selectedItemId: string | null;
setSelectedItem: (value: string | null) => void; setSelectedItem: (value: string | null) => void;
type?: string; handleScroll: () => void;
}; };
export const CustomSelect: FC<CustomSelectProps> = ({ export const CustomSelect: FC<CustomSelectProps> = ({
selectedItem, items,
selectedItemId,
setSelectedItem, setSelectedItem,
type, handleScroll,
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isMobile = useMediaQuery(theme.breakpoints.down(600));
const [opened, setOpened] = useState<boolean>(false);
const [currentValue, setCurrentValue] = useState<string | null>(selectedItem);
const [users, setUsers] = useState<User[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [page, setPage] = useState(1);
const [hasMoreItems, setHasMoreItems] = useState(true);
const SIZE = 25;
const ref = useRef<HTMLDivElement | null>(null); const ref = useRef<HTMLDivElement | null>(null);
const selectWidth = ref.current ? ref.current.offsetWidth : undefined;
const [savedValue, setSavedValue] = useState<number | null>(null); const [opened, setOpened] = useState<boolean>(false);
const [userName, setUserName] = useState<string>("");
const onSelectItem = useCallback(
(event: SelectChangeEvent<HTMLDivElement>) => {
const newValue = event.target.value.toString();
const selectedUser = users.find((user) => user.amoUserID == Number(newValue));
setUserName(selectedUser.name)
if (selectedUser) {
//для сохранения ID выбранного пользователя в стейт или конфиг...
setSavedValue(selectedUser.id);
}
setCurrentValue(newValue);
setSelectedItem(newValue);
},
[setSelectedItem, setCurrentValue, setSavedValue, users],
);
const toggleOpened = useCallback(() => { const toggleOpened = useCallback(() => {
setOpened((isOpened) => !isOpened); setOpened((isOpened) => !isOpened);
}, []); }, []);
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => { const onScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
const scrollHeight = e.currentTarget.scrollHeight; const scrollHeight = e.currentTarget.scrollHeight;
const scrollTop = e.currentTarget.scrollTop; const scrollTop = e.currentTarget.scrollTop;
const clientHeight = e.currentTarget.clientHeight; const clientHeight = e.currentTarget.clientHeight;
const scrolledToBottom = scrollTop / (scrollHeight - clientHeight) > 0.9; const scrolledToBottom = scrollTop / (scrollHeight - clientHeight) > 0.9;
if (scrolledToBottom && !isLoading && hasMoreItems) { if (scrolledToBottom) {
setPage((prevPage) => prevPage + 1); handleScroll();
} }
}; }, []);
useEffect(() => { const currentItem = useMemo(() => (
if (type === "typeUsers" && hasMoreItems) { items.find(item => item.id === selectedItemId) || null
setIsLoading(true); ), [selectedItemId, items])
const pagination: PaginationRequest = {
page: page,
size: SIZE,
};
getUsers(pagination).then(([response]) => {
if (response && response.items !== null) {
setUsers((prevItems) => [...prevItems, ...response.items]);
if (response.items.length < SIZE) {
setHasMoreItems(false);
}
}
setIsLoading(false);
});
}
}, [page, type, hasMoreItems]);
const menuItems = useMemo(() => { const menuItems = useMemo(() => {
if (type === "typeUsers" && users && users.length !== 0) { if (items.length !== 0) {
return users.map((user) => ( return items.map((item) => (
<MenuItem <MenuItem
key={user.amoUserID} key={item.id}
value={user.amoUserID} value={item.id}
sx={{ sx={{
padding: "6px 0", padding: "6px 0",
zIndex: 2, zIndex: 2,
@ -122,7 +93,7 @@ export const CustomSelect: FC<CustomSelectProps> = ({
padding: isMobile ? "5px 0 5px 20px" : "10px 0 10px 20px", padding: isMobile ? "5px 0 5px 20px" : "10px 0 10px 20px",
}} }}
> >
{user.name} {item.title}
</Typography> </Typography>
<Typography <Typography
sx={{ sx={{
@ -134,16 +105,7 @@ export const CustomSelect: FC<CustomSelectProps> = ({
color: isMobile ? "#9A9AAF" : "#4D4D4D", color: isMobile ? "#9A9AAF" : "#4D4D4D",
}} }}
> >
{user.email} {item.subTitle}
</Typography>
<Typography
sx={{
width: "33%",
padding: isMobile ? "5px 0 5px 20px" : "10px 0 10px 20px",
color: isMobile ? "#9A9AAF" : "#4D4D4D",
}}
>
{user.role}
</Typography> </Typography>
</Box> </Box>
</MenuItem> </MenuItem>
@ -154,7 +116,7 @@ export const CustomSelect: FC<CustomSelectProps> = ({
нет данных нет данных
</MenuItem> </MenuItem>
); );
}, [users, type]); }, [items]);
return ( return (
<Box> <Box>
@ -166,7 +128,7 @@ export const CustomSelect: FC<CustomSelectProps> = ({
height: "56px", height: "56px",
padding: "5px", padding: "5px",
color: color:
currentValue === null currentItem === null
? theme.palette.grey2.main ? theme.palette.grey2.main
: theme.palette.brightPurple.main, : theme.palette.brightPurple.main,
border: `2px solid ${theme.palette.common.white}`, border: `2px solid ${theme.palette.common.white}`,
@ -176,13 +138,13 @@ export const CustomSelect: FC<CustomSelectProps> = ({
alignItems: "center", alignItems: "center",
cursor: "pointer", cursor: "pointer",
}} }}
onClick={() => ref.current?.click()} onClick={() => {if (ref.current !== null) ref.current?.click()}}
> >
<Avatar sx={{ width: 46, height: 46, marginRight: 1 }} /> <Avatar sx={{ width: 46, height: 46, marginRight: 1 }} />
<Typography <Typography
sx={{ sx={{
marginLeft: isMobile ? "10px" : "20px", marginLeft: isMobile ? "10px" : "20px",
fontWeight: currentValue === null ? "400" : "500", fontWeight: currentItem === null ? "400" : "500",
fontSize: isMobile ? "14px" : "16px", fontSize: isMobile ? "14px" : "16px",
textOverflow: "ellipsis", textOverflow: "ellipsis",
whiteSpace: "nowrap", whiteSpace: "nowrap",
@ -190,7 +152,7 @@ export const CustomSelect: FC<CustomSelectProps> = ({
flexGrow: 1, flexGrow: 1,
}} }}
> >
{userName || "Выберите ответственного за сделку"} {currentItem?.title || "Выберите ответственного за сделку"}
</Typography> </Typography>
<img <img
src={arrow_down} src={arrow_down}
@ -214,18 +176,17 @@ export const CustomSelect: FC<CustomSelectProps> = ({
MenuProps={{ MenuProps={{
disablePortal: true, disablePortal: true,
PaperProps: { PaperProps: {
onScroll: handleScroll, onScroll: onScroll,
style: { style: {
zIndex: 2, zIndex: 2,
maxHeight: "300px", maxHeight: "300px",
overflow: "auto", overflow: "auto",
overflowX: "auto", overflowX: "auto",
maxWidth: selectWidth,
}, },
}, },
}} }}
sx={{}} sx={{}}
onChange={onSelectItem} onChange={({ target }: SelectChangeEvent<string>) => setSelectedItem(target.value)}
onClick={toggleOpened} onClick={toggleOpened}
> >
{menuItems} {menuItems}

@ -1,4 +1,4 @@
import React, { FC, useEffect, useMemo, useState } from "react"; import React, { FC, useCallback, useEffect, useMemo, useState } from "react";
import { import {
Dialog, Dialog,
IconButton, IconButton,
@ -24,15 +24,11 @@ import { AmoModalTitle } from "./AmoModalTitle/AmoModalTitle";
import { AmoSettingsBlock } from "./SettingsBlock/AmoSettingsBlock"; import { AmoSettingsBlock } from "./SettingsBlock/AmoSettingsBlock";
import { AmoAccountInfo } from "./AmoAccountInfo/AmoAccountInfo"; import { AmoAccountInfo } from "./AmoAccountInfo/AmoAccountInfo";
import { AccountResponse, IntegrationRules, Pipeline, Step, User, getAccount, getIntegrationRules, getPipelines, getSteps, getTags, getUsers, setIntegrationRules, updateIntegrationRules } from "@api/integration"; import { AccountResponse, IntegrationRules, Pipeline, Step, User, getAccount, getIntegrationRules, getPipelines, getSteps, getTags, getUsers, setIntegrationRules, updateIntegrationRules } from "@api/integration";
import { useAmoIntegration } from "./useAmoIntegration";
import { QuestionKeys, TagKeys } from "./types";
export type TitleKeys = "Company" | "Lead" | "Customer";
export type TagQuestionObject = {
backendId: string;
title: string;
};
export type TQuestionEntity = Record<TitleKeys, number[] | []>;
type IntegrationsModalProps = { type IntegrationsModalProps = {
isModalOpen: boolean; isModalOpen: boolean;
handleCloseModal: () => void; handleCloseModal: () => void;
@ -40,143 +36,85 @@ type IntegrationsModalProps = {
quizID: number | undefined; quizID: number | undefined;
}; };
export type TagKeys = "Contact" | "Company" | "Lead" | "Customer";
export type TTags = Record<TagKeys, number[] | []>;
export const AmoCRMModal: FC<IntegrationsModalProps> = ({ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
isModalOpen, isModalOpen,
handleCloseModal, handleCloseModal,
companyName, companyName,
quizID, quizID,
}) => { }) => {
//Если нет контекста квиза, то и делать на этой страничке нечего
if (quizID === undefined) {
redirect("/list");
return null;
}
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isMobile = useMediaQuery(theme.breakpoints.down(600));
const isTablet = useMediaQuery(theme.breakpoints.down(1000)); const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const { questions } = useQuestions(); 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 [step, setStep] = useState<number>(0); const [step, setStep] = useState<number>(0);
const [isSettingsBlock, setIsSettingsBlock] = useState<boolean>(false); const [isSettingsBlock, setIsSettingsBlock] = useState<boolean>(false);
const [isRemoveAccount, setIsRemoveAccount] = useState<boolean>(false); const [isTryRemoveAccount, setIsTryRemoveAccount] = useState<boolean>(false);
const [firstRules, setFirstRules] = useState<boolean>(false); const {
const [accountInfo, setAccountInfo] = useState<AccountResponse | null>(null); isloadingPage,
firstRules,
const [arrayOfPipelines, setArrayOfPipelines] = useState<Pipeline[]>([]); accountInfo,
const [arrayOfPipelinesSteps, setArrayOfPipelinesSteps] = useState<Step[]>([]); arrayOfPipelines,
const [arrayOfUsers, setArrayOfUsers] = useState<User[]>([]); arrayOfPipelinesSteps,
const [arrayOfTags, setArrayOfTags] = useState<TTags[]>([]); arrayOfUsers,
arrayOfTags,
const [selectedPipeline, setSelectedPipeline] = useState<number | null>(null); selectedPipeline,
const [selectedPipelineStep, setSelectedPipelineStep] = useState<number | null>(null); setSelectedPipeline,
const [selectedDealPerformer, setSelectedDealPerformer] = useState<number | null>(null); selectedPipelineStep,
setSelectedPipelineStep,
const [questionEntityBackend, setQuestionEntityBackend] = useState<TQuestionEntity>({}); selectedDealUser,
const [questionEntity, setQuestionEntity] = useState<TQuestionEntity>({ setSelectedDealPerformer,
Lead: [], questionEntityBackend,
Company: [], selectedTags,
Customer: [], setSelectedTags,
}); selectedQuestions,
const [tags, setTags] = useState<TTags>({ setSelectedQuestions,
Lead: [], setPageOfPipelines,
Contact: [], setPageOfPipelinesSteps,
Company: [], setPageOfUsers,
Customer: [], setPageOfTags,
}); } = useAmoIntegration({
quizID,
useEffect(() => { isModalOpen,
if (isModalOpen && quizID !== undefined && !isRemoveAccount) { isTryRemoveAccount,
const fetchAccount = async () => {
const [account, error] = await getAccount();
if (error) {
if (!error.includes("Not Found")) enqueueSnackbar(error)
setAccountInfo(null);
}
if (account) {
setAccountInfo(account);
}
};
const fetchRules = async () => {
const [settingsResponse, error] = await getIntegrationRules(quizID.toString());
if (error) {
if (error === "first") setFirstRules(true);
if (!error.includes("Not Found") && !error.includes("first")) enqueueSnackbar(error);
}
if (settingsResponse) {
if (settingsResponse.PipelineID) setSelectedPipeline(settingsResponse.PipelineID)
if (settingsResponse.StepID) setSelectedPipelineStep(settingsResponse.StepID)
if (settingsResponse.PerformerID) setSelectedDealPerformer(settingsResponse.PerformerID)
if (Boolean(settingsResponse.FieldsRule) &&
Object.keys(settingsResponse.FieldsRule).length > 0) {
const newRules = { ...questionEntity }
setQuestionEntityBackend(settingsResponse.FieldsRule)
for (let key in settingsResponse.FieldsRule) {
if (settingsResponse.FieldsRule[key] !== null && Array.isArray(settingsResponse.FieldsRule[key])) {
const gottenList = Object.keys(settingsResponse.FieldsRule[key][0].QuestionID)
newRules[key] = gottenList
}
}
setQuestionEntity(newRules)
}
if (Boolean(settingsResponse.TagsToAdd) &&
Object.keys(settingsResponse.TagsToAdd).length > 0) {
const newRules = { ...tags }
for (let key in settingsResponse.TagsToAdd) {
const gottenList = settingsResponse.TagsToAdd[key]
if (gottenList !== null && Array.isArray(gottenList)) {
newRules[key] = gottenList
}
}
setTags(newRules)
}
setFirstRules(false);
}
};
getTags({
page: 1,
size: 9999,
}).then(([response]) => {
if (response && response.items !== null) {
setArrayOfTags(response.items);
}
});
getUsers({
page: 1,
size: 9999,
}).then(([response]) => {
if (response && response.items !== null) {
setArrayOfUsers(response.items);
}
});
getPipelines({
page: 1,
size: 9999,
}).then(([response]) => {
if (response && response.items !== null) {
setArrayOfPipelines(response.items);
}
}) })
fetchAccount(); const handleAddTagQuestion = useCallback((scope: QuestionKeys | TagKeys, id: string, type: "question" | "tag") => {
fetchRules(); if (!scope || !id) return;
if (type === "tag") {
setSelectedTags((prevState) => ({
...prevState,
[scope]: [...prevState[scope as TagKeys], id],
}));
} }
}, [isModalOpen, isRemoveAccount]);
useEffect(() => { if (type === "question") {
if (selectedPipeline !== null) setSelectedQuestions((prevState) => ({
getSteps({ ...prevState,
page: 1, [scope]: [...prevState[scope as QuestionKeys], id],
size: 9999, }));
pipelineId: selectedPipeline,
}).then(([response]) => {
if (response && response.items !== null) {
setArrayOfPipelinesSteps(response.items);
} }
}); }, [setSelectedQuestions, setSelectedTags]);
}, [selectedPipeline])
const handleNextStep = () => { const handleNextStep = () => {
setStep((prevState) => prevState + 1); setStep((prevState) => prevState + 1);
@ -189,7 +127,7 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
console.log({ console.log({
PipelineID: Number(selectedPipeline), PipelineID: Number(selectedPipeline),
StepID: Number(selectedPipelineStep), StepID: Number(selectedPipelineStep),
PerformerID: Number(selectedDealPerformer), PerformerID: Number(selectedDealUser),
FieldsRule: questionEntity, FieldsRule: questionEntity,
TagsToAdd: tags TagsToAdd: tags
}) })
@ -200,7 +138,7 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
const body = { const body = {
PipelineID: Number(selectedPipeline), PipelineID: Number(selectedPipeline),
StepID: Number(selectedPipelineStep), StepID: Number(selectedPipelineStep),
PerformerID: Number(selectedDealPerformer), PerformerID: Number(selectedDealUser),
FieldsRule: questionEntityBackend, FieldsRule: questionEntityBackend,
TagsToAdd: tags TagsToAdd: tags
} }
@ -252,8 +190,8 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
<Pipelines <Pipelines
handlePrevStep={handlePrevStep} handlePrevStep={handlePrevStep}
handleNextStep={handleNextStep} handleNextStep={handleNextStep}
selectedPipelinePerformer={selectedDealPerformer} selectedPipelinePerformer={selectedDealUser}
setSelectedPipelinePerformer={setSelectedDealPerformer} setSelectedPipelineUser={setSelectedDealPerformer}
selectedPipeline={selectedPipeline} selectedPipeline={selectedPipeline}
setSelectedPipeline={setSelectedPipeline} setSelectedPipeline={setSelectedPipeline}
/> />
@ -266,7 +204,7 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
<PipelineSteps <PipelineSteps
handlePrevStep={handlePrevStep} handlePrevStep={handlePrevStep}
handleNextStep={handleNextStep} handleNextStep={handleNextStep}
selectedStepsPerformer={selectedDealPerformer} selectedStepsPerformer={selectedDealUser}
setSelectedStepsPerformer={setSelectedDealPerformer} setSelectedStepsPerformer={setSelectedDealPerformer}
selectedStep={selectedPipelineStep} selectedStep={selectedPipelineStep}
setSelectedStep={setSelectedPipelineStep} setSelectedStep={setSelectedPipelineStep}
@ -281,7 +219,7 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
<DealPerformers <DealPerformers
handlePrevStep={handlePrevStep} handlePrevStep={handlePrevStep}
handleNextStep={handleNextStep} handleNextStep={handleNextStep}
selectedDealPerformer={selectedDealPerformer} selectedDealUser={selectedDealUser}
setSelectedDealPerformer={setSelectedDealPerformer} setSelectedDealPerformer={setSelectedDealPerformer}
/> />
), ),
@ -291,11 +229,12 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
isSettingsAvailable: true, isSettingsAvailable: true,
component: ( component: (
<AmoTags <AmoTags
tagsNames={tags} tagsItems={arrayOfTags}
selectedTags={selectedTags}
handleScroll={()=>{}}
handleAddTag={handleAddTagQuestion}
handlePrevStep={handlePrevStep} handlePrevStep={handlePrevStep}
handleNextStep={handleNextStep} handleNextStep={handleNextStep}
setIdTags={setTags}
arrayOfTags={arrayOfTags}
/> />
), ),
}, },
@ -304,30 +243,25 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
isSettingsAvailable: true, isSettingsAvailable: true,
component: ( component: (
<AmoQuestions <AmoQuestions
questionEntity={questionEntity} questionsItems={minifiedQuestions}
setQuestionEntity={setQuestionEntity} selectedQuestions={selectedQuestions}
handleAddQuestion={handleAddTagQuestion}
handlePrevStep={handlePrevStep} handlePrevStep={handlePrevStep}
handleNextStep={handleSave} handleNextStep={handleSave}
questions={questions}
/> />
), ),
}, },
], ],
[ [
accountInfo, arrayOfPipelines,
questionEntity, arrayOfPipelinesSteps,
selectedPipeline, arrayOfUsers,
selectedPipelineStep, arrayOfTags,
selectedDealPerformer,
tags,
], ],
); );
const stepTitles = steps.map((step) => step.title); const stepTitles = steps.map((step) => step.title);
//Если нет контекста квиза, то и делать на этой страничке нечего
if (quizID === undefined) return redirect("/list")
return ( return (
<Dialog <Dialog
open={isModalOpen} open={isModalOpen}
@ -390,11 +324,11 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
isSettingsBlock={isSettingsBlock} isSettingsBlock={isSettingsBlock}
setIsSettingsBlock={setIsSettingsBlock} setIsSettingsBlock={setIsSettingsBlock}
setStep={setStep} setStep={setStep}
startRemoveAccount={() => setIsRemoveAccount(true)} startRemoveAccount={() => setIsTryRemoveAccount(true)}
/> />
{isRemoveAccount && ( {isTryRemoveAccount && (
<AmoRemoveAccount <AmoRemoveAccount
stopThisPage={() => setIsRemoveAccount(false)} stopThisPage={() => setIsTryRemoveAccount(false)}
/> />
)} )}
{isSettingsBlock && ( {isSettingsBlock && (
@ -403,15 +337,15 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({
stepTitles={stepTitles} stepTitles={stepTitles}
setIsSettingsBlock={setIsSettingsBlock} setIsSettingsBlock={setIsSettingsBlock}
setStep={setStep} setStep={setStep}
selectedDealPerformer={arrayOfUsers.find(p => p.amoUserID == selectedDealPerformer)?.name || null} selectedDealUser={selectedDealUser}
selectedFunnel={arrayOfPipelines.find(p => selectedPipeline)?.Name || null} selectedFunnel={selectedPipeline}
selectedStage={arrayOfPipelinesSteps.find(p => selectedPipelineStep)?.Name || null} selectedStage={selectedPipelineStep}
questionEntity={questionEntity} selectedQuestions={selectedQuestions}
tags={tags} selectedTags={selectedTags}
/> />
</Box> </Box>
)} )}
{!isSettingsBlock && !isRemoveAccount && ( {!isSettingsBlock && !isTryRemoveAccount && (
<Box sx={{ flexGrow: 1, width: "100%" }}>{steps[step].component}</Box> <Box sx={{ flexGrow: 1, width: "100%" }}>{steps[step].component}</Box>
)} )}
</Box> </Box>

@ -1,79 +1,40 @@
import { useTheme } from "@mui/material";
import { import {
Dispatch,
FC, FC,
SetStateAction,
useCallback,
useMemo,
useState, useState,
} from "react"; } from "react";
import { ItemsSelectionView } from "./ItemsSelectionView/ItemsSelectionView"; import { ItemsSelectionView } from "./ItemsSelectionView/ItemsSelectionView";
import { ItemDetailsView } from "./ItemDetailsView/ItemDetailsView"; import { ItemDetailsView } from "./ItemDetailsView/ItemDetailsView";
import { TagQuestionObject, TitleKeys, TQuestionEntity } from "../AmoCRMModal"; import { Box } from "@mui/material";
import Box from "@mui/material/Box"; import { QuestionKeys, SelectedQuestions, TagKeys } from "../types";
import type { AllTypesQuestion } from "@model/questionTypes/shared"
import { getQuestionById } from "@/stores/questions/actions";
import { useQuestionsStore } from "@/stores/questions/store";
type Items = {
id: string;
title: string;
subTitle?: string;
};
type Props = { type Props = {
questionsItems: Items[] | [];
selectedQuestions: SelectedQuestions;
handleAddQuestion: (scope: QuestionKeys | TagKeys, id: string, type: "question" | "tag") => void;
handlePrevStep: () => void; handlePrevStep: () => void;
handleNextStep: () => void; handleNextStep: () => void;
questionEntity: TQuestionEntity;
setQuestionEntity: Dispatch<SetStateAction<TQuestionEntity>>;
questions: AllTypesQuestion[];
}; };
export const AmoQuestions: FC<Props> = ({ export const AmoQuestions: FC<Props> = ({
questionsItems,
selectedQuestions,
handleAddQuestion,
handlePrevStep, handlePrevStep,
handleNextStep, handleNextStep,
questionEntity,
setQuestionEntity,
questions,
}) => { }) => {
const theme = useTheme();
const [isSelection, setIsSelection] = useState<boolean>(false); const [isSelection, setIsSelection] = useState<boolean>(false);
const [activeItem, setActiveItem] = useState<string | null>(null); const [activeScope, setActiveScope] = useState<QuestionKeys | null>(null);
const [selectedValue, setSelectedValue] = useState<string | null>(null); const [selectedQuestion, setSelectedQuestion] = useState<string | null>(null);
const handleAdd = useCallback(() => { const handleAdd = () => {
if (!activeItem || !selectedValue) return; if (activeScope === null || selectedQuestion === null) return
handleAddQuestion(activeScope, selectedQuestion, "question")
setQuestionEntity((prevState) => ({
...prevState,
[activeItem]: [...prevState[activeItem as TitleKeys], Number(selectedValue)],
}));
}, [activeItem, setQuestionEntity, selectedValue]);
const items: TagQuestionObject[] = useMemo(
() => Object.values(questions)
.filter(({ type }) =>
type !== "result"
&& type !== null)
.map(({ backendId, title }) => ({
backendId: backendId,
title
})),
[],
);
const translatedQuestionEntity = useMemo(() => {
const translated = {
} as TQuestionEntity;
for (let key in questionEntity) {
if (questionEntity[key] !== "Contact") {
console.log(translated)
console.log(translated[key])
console.log(questionEntity)
translated[key] = questionEntity[key].map((id) =>
questions.find((q) => q.backendId === Number(id))?.title || id)
} }
}
return translated
},
[questionEntity],
)
return ( return (
<Box <Box
@ -84,29 +45,29 @@ export const AmoQuestions: FC<Props> = ({
flexGrow: 1, flexGrow: 1,
}} }}
> >
{isSelection ? ( {isSelection && activeScope !== null ? (
// Здесь выбираем элемент в табличку
<ItemsSelectionView <ItemsSelectionView
items={items} items={questionsItems}
type="typeQuestions" setSelectedItem={setSelectedQuestion}
selectedValue={selectedValue}
setSelectedValue={setSelectedValue}
onSmallBtnClick={() => { onSmallBtnClick={() => {
setActiveItem(null); setActiveScope(null);
setIsSelection(false); setIsSelection(false);
}} }}
onLargeBtnClick={() => { onLargeBtnClick={() => {
handleAdd(); handleAdd();
setActiveItem(null); setActiveScope(null);
setIsSelection(false); setIsSelection(false);
}} }}
/> />
) : ( ) : (
// Табличка
<ItemDetailsView <ItemDetailsView
setActiveScope={setActiveScope}
selectedQuestions={selectedQuestions}
setIsSelection={setIsSelection} setIsSelection={setIsSelection}
handleLargeBtn={handleNextStep} handleLargeBtn={handleNextStep}
handleSmallBtn={handlePrevStep} handleSmallBtn={handlePrevStep}
questionEntity={translatedQuestionEntity}
setActiveItem={setActiveItem}
/> />
)} )}
</Box> </Box>

@ -2,7 +2,7 @@ import { Box, useTheme } from "@mui/material";
import { Item } from "../Item/Item"; import { Item } from "../Item/Item";
import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock"; import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock";
import { FC } from "react"; import { FC } from "react";
import { TQuestionEntity } from "../../AmoCRMModal"; import { QuestionKeys, SelectedQuestions } from "../../types";
type TitleKeys = "Contact" | "Company" | "Lead" | "Customer"; type TitleKeys = "Contact" | "Company" | "Lead" | "Customer";
@ -10,16 +10,16 @@ type ItemDetailsViewProps = {
setIsSelection: (value: boolean) => void; setIsSelection: (value: boolean) => void;
handleSmallBtn: () => void; handleSmallBtn: () => void;
handleLargeBtn: () => void; handleLargeBtn: () => void;
questionEntity: TQuestionEntity; selectedQuestions: SelectedQuestions;
setActiveItem: (value: string | null) => void; setActiveScope: (value: QuestionKeys | null) => void;
}; };
export const ItemDetailsView: FC<ItemDetailsViewProps> = ({ export const ItemDetailsView: FC<ItemDetailsViewProps> = ({
handleSmallBtn, handleSmallBtn,
handleLargeBtn, handleLargeBtn,
questionEntity, selectedQuestions,
setActiveItem,
setIsSelection, setIsSelection,
setActiveScope,
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
@ -48,16 +48,16 @@ export const ItemDetailsView: FC<ItemDetailsViewProps> = ({
justifyContent: "start", justifyContent: "start",
}} }}
> >
{questionEntity && {selectedQuestions &&
Object.keys(questionEntity).map((item) => ( Object.keys(selectedQuestions).map((item) => (
<Item <Item
key={item} key={item}
title={item as TitleKeys} title={item}
onAddBtnClick={() => { onAddBtnClick={() => {
setIsSelection(true); setIsSelection(true);
setActiveItem(item); setActiveScope(item as QuestionKeys);
}} }}
data={questionEntity} data={selectedQuestions}
/> />
))} ))}
</Box> </Box>

@ -2,30 +2,28 @@ import { Box } from "@mui/material";
import { CustomRadioGroup } from "../../../../../components/CustomRadioGroup/CustomRadioGroup"; import { CustomRadioGroup } from "../../../../../components/CustomRadioGroup/CustomRadioGroup";
import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock"; import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock";
import { FC } from "react"; import { FC } from "react";
import { AllTypesQuestion } from "@/model/questionTypes/shared";
import type { TagQuestionObject } from "@/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal"
import { Tag } from "@api/integration";
type Items = {
id: string;
title: string;
subTitle?: string;
};
type ItemsSelectionViewProps = { type ItemsSelectionViewProps = {
type?: string; items: Items[] | [];
items?: TagQuestionObject[]; selectedItemId?: string | null;
selectedValue: string | null; setSelectedItem: (value: string | null) => void;
setSelectedValue: (value: string | null) => void; handleScroll?: () => void;
onLargeBtnClick: () => void; onLargeBtnClick: () => void;
onSmallBtnClick: () => void; onSmallBtnClick: () => void;
setTags: (setValueFunc: (value: Tag[]) => Tag[]) => void;
parentTags: Tag[]
}; };
export const ItemsSelectionView: FC<ItemsSelectionViewProps> = ({ export const ItemsSelectionView: FC<ItemsSelectionViewProps> = ({
items, items,
selectedValue, selectedItemId,
setSelectedValue, setSelectedItem,
handleScroll,
onLargeBtnClick, onLargeBtnClick,
onSmallBtnClick, onSmallBtnClick,
type,
parentTags,
setTags
}) => { }) => {
return ( return (
<Box <Box
@ -46,12 +44,10 @@ export const ItemsSelectionView: FC<ItemsSelectionViewProps> = ({
}} }}
> >
<CustomRadioGroup <CustomRadioGroup
type={type}
items={items} items={items}
tags={parentTags} selectedItemId={selectedItemId}
setTags={setTags} setSelectedItem={setSelectedItem}
selectedValue={selectedValue} handleScroll={handleScroll}
setSelectedValue={setSelectedValue}
/> />
</Box> </Box>
<Box <Box

@ -1,58 +1,42 @@
import { useTheme } from "@mui/material";
import { import {
Dispatch,
FC, FC,
SetStateAction,
useCallback,
useEffect,
useMemo,
useState, useState,
} from "react"; } from "react";
import { Box } from "@mui/material";
import { TagKeys, TagQuestionObject, TTags } from "../AmoCRMModal";
import Box from "@mui/material/Box";
import { ItemsSelectionView } from "../AmoQuestions/ItemsSelectionView/ItemsSelectionView"; import { ItemsSelectionView } from "../AmoQuestions/ItemsSelectionView/ItemsSelectionView";
import { TagsDetailsView } from "./TagsDetailsView/TagsDetailsView"; import { TagsDetailsView } from "./TagsDetailsView/TagsDetailsView";
import { Tag } from "@api/integration"; import { QuestionKeys, SelectedTags, TagKeys } from "../types";
type Items = {
id: string;
title: string;
subTitle?: string;
};
type Props = { type Props = {
handleNextStep: () => void; tagsItems: Items[] | [];
selectedTags: SelectedTags;
handleAddTag: (scope: QuestionKeys | TagKeys, id: string, type: "question" | "tag") => void;
handleScroll: () => void;
handlePrevStep: () => void; handlePrevStep: () => void;
tagsNames: TTags; handleNextStep: () => void;
setIdTags: Dispatch<SetStateAction<TTags>>;
arrayOfTags: TTags[]
}; };
export const AmoTags: FC<Props> = ({ export const AmoTags: FC<Props> = ({
handleNextStep, tagsItems,
selectedTags,
handleAddTag,
handleScroll,
handlePrevStep, handlePrevStep,
tagsNames, handleNextStep,
setIdTags,
arrayOfTags,
}) => { }) => {
const theme = useTheme();
const [isSelection, setIsSelection] = useState<boolean>(false); const [isSelection, setIsSelection] = useState<boolean>(false);
const [activeTag, setActiveItem] = useState<string | null>(null); const [activeScope, setActiveScope] = useState<TagKeys | null>(null);
const [selectedValue, setSelectedValue] = useState<string | null>(null); const [selectedTag, setSelectedTag] = useState<string | null>(null);
const [tags, setTags] = useState<Tag[]>([]);
const [tagsNamesList, setTagsNamesList] = useState<Record<TagKeys, string[]>>({
Lead: [],
Contact: [],
Company: [],
Customer: [],
});
const handleAdd = useCallback(() => {
if (!activeTag || !selectedValue) return;
setIdTags((prevState) => ({ const handleAdd = () => {
...prevState, if (activeScope === null || selectedTag === null) return
[activeTag]: [...prevState[activeTag as TagKeys], Number(selectedValue)], handleAddTag(activeScope, selectedTag, "tag")
})); }
setTagsNamesList((prevState) => ({
...prevState,
[activeTag]: [...prevState[activeTag as TagKeys], arrayOfTags.find((tag) => tag.AmoID == selectedValue).Name],
}));
}, [activeTag, setIdTags, selectedValue]);
return ( return (
<Box <Box
@ -63,31 +47,30 @@ export const AmoTags: FC<Props> = ({
flexGrow: 1, flexGrow: 1,
}} }}
> >
{isSelection ? ( {isSelection && activeScope !== null ? (
// Здесь выбираем элемент в табличку
<ItemsSelectionView <ItemsSelectionView
parentTags={tags} items={tagsItems}
setTags={setTags} setSelectedItem={setSelectedTag}
selectedValue={selectedValue} handleScroll={handleScroll}
setSelectedValue={setSelectedValue}
type={"typeTags"}
onSmallBtnClick={() => { onSmallBtnClick={() => {
setActiveItem(null); setActiveScope(null);
setIsSelection(false); setIsSelection(false);
}} }}
onLargeBtnClick={() => { onLargeBtnClick={() => {
handleAdd(); handleAdd();
setActiveItem(null); setActiveScope(null);
setIsSelection(false); setIsSelection(false);
}} }}
/> />
) : ( ) : (
// Табличка
<TagsDetailsView <TagsDetailsView
tagsNamesList={tagsNamesList} setActiveScope={setActiveScope}
selectedTags={selectedTags}
setIsSelection={setIsSelection} setIsSelection={setIsSelection}
handlePrevStep={handlePrevStep}
handleNextStep={handleNextStep} handleNextStep={handleNextStep}
tagsNames={tagsNames} handlePrevStep={handlePrevStep}
setActiveItem={setActiveItem}
/> />
)} )}
</Box> </Box>

@ -1,25 +1,23 @@
import { Box, Typography, useTheme } from "@mui/material"; import { Box, Typography, useTheme } from "@mui/material";
import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock"; import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock";
import { FC } from "react"; import { FC } from "react";
import { TagKeys, TitleKeys, TTags } from "../../AmoCRMModal";
import { Item } from "../../AmoQuestions/Item/Item"; import { Item } from "../../AmoQuestions/Item/Item";
import { SelectedTags, TagKeys } from "../../types";
type TagsDetailsViewProps = { type TagsDetailsViewProps = {
setIsSelection: (value: boolean) => void; setIsSelection: (value: boolean) => void;
handlePrevStep: () => void; handlePrevStep: () => void;
handleNextStep: () => void; handleNextStep: () => void;
tagsNames: TTags; setActiveScope: (value: TagKeys | null) => void;
setActiveItem: (value: string | null) => void; selectedTags: SelectedTags;
tagsNamesList: Record<TagKeys, string[]>
}; };
export const TagsDetailsView: FC<TagsDetailsViewProps> = ({ export const TagsDetailsView: FC<TagsDetailsViewProps> = ({
setActiveScope,
selectedTags,
setIsSelection,
handlePrevStep, handlePrevStep,
handleNextStep, handleNextStep,
tagsNames,
setActiveItem,
setIsSelection,
tagsNamesList,
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
@ -70,17 +68,16 @@ export const TagsDetailsView: FC<TagsDetailsViewProps> = ({
justifyContent: "start", justifyContent: "start",
}} }}
> >
{tagsNames && {selectedTags &&
Object.keys(tagsNames).map((item) => ( Object.keys(selectedTags).map((item) => (
<Item <Item
tagsNamesList={tagsNamesList}
key={item} key={item}
title={item as TitleKeys} title={item}
onAddBtnClick={() => { onAddBtnClick={() => {
setIsSelection(true); setIsSelection(true);
setActiveItem(item); setActiveScope(item as TagKeys);
}} }}
data={tagsNames} data={selectedTags}
/> />
))} ))}
</Box> </Box>

@ -6,14 +6,14 @@ import { CustomSelect } from "../../../../components/CustomSelect/CustomSelect";
type Props = { type Props = {
handlePrevStep: () => void; handlePrevStep: () => void;
handleNextStep: () => void; handleNextStep: () => void;
selectedDealPerformer: number | null; selectedDealUser: string | null;
setSelectedDealPerformer: (value: number | null) => void; setSelectedDealPerformer: (value: string | null) => void;
}; };
export const DealPerformers: FC<Props> = ({ export const DealPerformers: FC<Props> = ({
handlePrevStep, handlePrevStep,
handleNextStep, handleNextStep,
selectedDealPerformer, selectedDealUser,
setSelectedDealPerformer, setSelectedDealPerformer,
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
@ -32,9 +32,10 @@ export const DealPerformers: FC<Props> = ({
> >
<Box sx={{ width: "100%", marginTop: "20px", zIndex: 3 }}> <Box sx={{ width: "100%", marginTop: "20px", zIndex: 3 }}>
<CustomSelect <CustomSelect
selectedItem={selectedDealPerformer} items={ }
setSelectedItem={setSelectedDealPerformer} selectedItemId={ }
type={"typeUsers"} setSelectedItem={ }
handleScroll={ }
/> />
</Box> </Box>
<Box <Box

@ -7,11 +7,11 @@ import { CustomRadioGroup } from "../../../../components/CustomRadioGroup/Custom
type Props = { type Props = {
handlePrevStep: () => void; handlePrevStep: () => void;
handleNextStep: () => void; handleNextStep: () => void;
selectedStepsPerformer: number | null; selectedStepsPerformer: string | null;
setSelectedStepsPerformer: (value: number | null) => void; setSelectedStepsPerformer: (value: string | null) => void;
selectedStep: number | null; selectedStep: string | null;
setSelectedStep: (value: number | null) => void; setSelectedStep: (value: string | null) => void;
pipelineId: number | null; pipelineId: string | null;
}; };
export const PipelineSteps: FC<Props> = ({ export const PipelineSteps: FC<Props> = ({
@ -39,9 +39,10 @@ export const PipelineSteps: FC<Props> = ({
> >
<Box sx={{ width: "100%", marginTop: "20px", zIndex: 3 }}> <Box sx={{ width: "100%", marginTop: "20px", zIndex: 3 }}>
<CustomSelect <CustomSelect
selectedItem={selectedStepsPerformer} items={ }
type={"typeUsers"} selectedItemId={ }
setSelectedItem={setSelectedStepsPerformer} setSelectedItem={ }
handleScroll={ }
/> />
</Box> </Box>
<Box <Box
@ -53,11 +54,10 @@ export const PipelineSteps: FC<Props> = ({
}} }}
> >
<CustomRadioGroup <CustomRadioGroup
// @ts-ignore items={ }
pipelineId={pipelineId} selectedItemId={ }
type={"typeSteps"} setSelectedItem={ }
selectedValue={selectedStep} handleScroll={ }
setSelectedValue={setSelectedStep}
/> />
</Box> </Box>
<Box <Box

@ -7,10 +7,10 @@ import { CustomRadioGroup } from "../../../../components/CustomRadioGroup/Custom
type Props = { type Props = {
handlePrevStep: () => void; handlePrevStep: () => void;
handleNextStep: () => void; handleNextStep: () => void;
selectedPipelinePerformer: number | null; selectedPipelinePerformer: string | null;
setSelectedPipelinePerformer: (value: number | null) => void; setSelectedPipelineUser: (value: string | null) => void;
selectedPipeline: number | null; selectedPipeline: string | null;
setSelectedPipeline: (value: number | null) => void; setSelectedPipeline: (value: string | null) => void;
}; };
@ -18,7 +18,7 @@ export const Pipelines: FC<Props> = ({
handlePrevStep, handlePrevStep,
handleNextStep, handleNextStep,
selectedPipelinePerformer, selectedPipelinePerformer,
setSelectedPipelinePerformer, setSelectedPipelineUser,
selectedPipeline, selectedPipeline,
setSelectedPipeline, setSelectedPipeline,
}) => { }) => {
@ -37,9 +37,10 @@ export const Pipelines: FC<Props> = ({
> >
<Box sx={{ width: "100%", marginTop: "20px", zIndex: 3 }}> <Box sx={{ width: "100%", marginTop: "20px", zIndex: 3 }}>
<CustomSelect <CustomSelect
selectedItem={selectedPipelinePerformer} items={ }
setSelectedItem={setSelectedPipelinePerformer} selectedItemId={ }
type={"typeUsers"} setSelectedItem={ }
handleScroll={ }
/> />
</Box> </Box>
<Box <Box
@ -51,9 +52,10 @@ export const Pipelines: FC<Props> = ({
}} }}
> >
<CustomRadioGroup <CustomRadioGroup
selectedValue={selectedPipeline} items={ }
setSelectedValue={setSelectedPipeline} selectedItemId={ }
type={"typePipelines"} setSelectedItem={ }
handleScroll={ }
/> />
</Box> </Box>
<Box <Box

@ -2,17 +2,17 @@ import { FC } from "react";
import { Box, useMediaQuery, useTheme } from "@mui/material"; import { Box, useMediaQuery, useTheme } from "@mui/material";
import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock";
import { SettingItem } from "./SettingItem/SettingItem"; import { SettingItem } from "./SettingItem/SettingItem";
import { TQuestionEntity, TTags } from "../AmoCRMModal"; import { SelectedQuestions, SelectedTags } from "../types";
type AmoSettingsBlockProps = { type AmoSettingsBlockProps = {
stepTitles: string[]; stepTitles: string[];
setStep: (value: number) => void; setStep: (value: number) => void;
setIsSettingsBlock: (value: boolean) => void; setIsSettingsBlock: (value: boolean) => void;
selectedFunnel: number | null; selectedFunnel: string | null;
selectedStage: number | null; selectedStage: string | null;
selectedDealPerformer: string | null; selectedDealUser: string | null;
questionEntity: TQuestionEntity; selectedQuestions: SelectedQuestions;
tags: TTags; selectedTags: SelectedTags;
}; };
export const AmoSettingsBlock: FC<AmoSettingsBlockProps> = ({ export const AmoSettingsBlock: FC<AmoSettingsBlockProps> = ({
@ -20,10 +20,10 @@ export const AmoSettingsBlock: FC<AmoSettingsBlockProps> = ({
setStep, setStep,
setIsSettingsBlock, setIsSettingsBlock,
selectedFunnel, selectedFunnel,
selectedDealPerformer, selectedDealUser,
selectedStage, selectedStage,
questionEntity, selectedQuestions,
tags, selectedTags,
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isMobile = useMediaQuery(theme.breakpoints.down(600));
@ -57,11 +57,11 @@ export const AmoSettingsBlock: FC<AmoSettingsBlockProps> = ({
title={title} title={title}
setIsSettingsBlock={setIsSettingsBlock} setIsSettingsBlock={setIsSettingsBlock}
setStep={setStep} setStep={setStep}
selectedDealPerformer={selectedDealPerformer} selectedDealUser={selectedDealUser}
selectedFunnel={selectedFunnel} selectedFunnel={selectedFunnel}
selectedStage={selectedStage} selectedStage={selectedStage}
questionEntity={questionEntity} selectedQuestions={selectedQuestions}
tags={tags} selectedTags={selectedTags}
/> />
))} ))}
</Box> </Box>

@ -4,7 +4,7 @@ import { Typography, useMediaQuery, useTheme } from "@mui/material";
import { SettingItemHeader } from "./SettingItemHeader/SettingItemHeader"; import { SettingItemHeader } from "./SettingItemHeader/SettingItemHeader";
import { ResponsiblePerson } from "./ResponsiblePerson/ResponsiblePerson"; import { ResponsiblePerson } from "./ResponsiblePerson/ResponsiblePerson";
import { SelectedParameter } from "./SelectedParameter/SelectedParameter"; import { SelectedParameter } from "./SelectedParameter/SelectedParameter";
import { TQuestionEntity, TTags } from "../../AmoCRMModal"; import { SelectedQuestions, SelectedTags } from "../../types";
type SettingItemProps = { type SettingItemProps = {
step: number; step: number;
@ -14,10 +14,10 @@ type SettingItemProps = {
selectedFunnelPerformer: string | null; selectedFunnelPerformer: string | null;
selectedFunnel: string | null; selectedFunnel: string | null;
selectedStagePerformer: string | null; selectedStagePerformer: string | null;
selectedDealPerformer: string | null; selectedDealUser: string | null;
selectedStage: string | null; selectedStage: string | null;
questionEntity: TQuestionEntity; selectedQuestions: SelectedQuestions;
tags: TTags; selectedTags: SelectedTags;
}; };
export const SettingItem: FC<SettingItemProps> = ({ export const SettingItem: FC<SettingItemProps> = ({
@ -28,10 +28,10 @@ export const SettingItem: FC<SettingItemProps> = ({
selectedFunnelPerformer, selectedFunnelPerformer,
selectedFunnel, selectedFunnel,
selectedStagePerformer, selectedStagePerformer,
selectedDealPerformer, selectedDealUser,
selectedStage, selectedStage,
questionEntity, selectedQuestions,
tags, selectedTags,
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isMobile = useMediaQuery(theme.breakpoints.down(600));
@ -43,7 +43,7 @@ export const SettingItem: FC<SettingItemProps> = ({
if (step === 1) { if (step === 1) {
return ( return (
<> <>
<ResponsiblePerson performer={selectedDealPerformer} /> <ResponsiblePerson performer={selectedDealUser} />
<SelectedParameter parameter={selectedFunnel} /> <SelectedParameter parameter={selectedFunnel} />
</> </>
); );
@ -51,7 +51,7 @@ export const SettingItem: FC<SettingItemProps> = ({
if (step === 2) { if (step === 2) {
return ( return (
<> <>
<ResponsiblePerson performer={selectedDealPerformer} /> <ResponsiblePerson performer={selectedDealUser} />
<SelectedParameter parameter={selectedStage} /> <SelectedParameter parameter={selectedStage} />
</> </>
); );
@ -59,12 +59,12 @@ export const SettingItem: FC<SettingItemProps> = ({
if (step === 3) { if (step === 3) {
return ( return (
<> <>
<ResponsiblePerson performer={selectedDealPerformer} /> <ResponsiblePerson performer={selectedDealUser} />
</> </>
); );
} }
if (step === 4) { if (step === 4) {
const isFilled = Object.values(questionEntity).some( const isFilled = Object.values(selectedQuestions).some(
(array) => array.length > 0, (array) => array.length > 0,
); );
const status = isFilled ? "Заполнено" : "Не заполнено"; const status = isFilled ? "Заполнено" : "Не заполнено";
@ -96,7 +96,7 @@ export const SettingItem: FC<SettingItemProps> = ({
); );
} }
if (step === 5) { if (step === 5) {
const isFilled = Object.values(tags).some((array) => array.length > 0); const isFilled = Object.values(selectedTags).some((array) => array.length > 0);
const status = isFilled ? "Заполнено" : "Не заполнено"; const status = isFilled ? "Заполнено" : "Не заполнено";
return ( return (
@ -131,10 +131,10 @@ export const SettingItem: FC<SettingItemProps> = ({
selectedFunnelPerformer, selectedFunnelPerformer,
selectedFunnel, selectedFunnel,
selectedStagePerformer, selectedStagePerformer,
selectedDealPerformer, selectedDealUser,
selectedStage, selectedStage,
questionEntity, selectedQuestions,
tags, selectedTags,
]); ]);
return ( return (

@ -0,0 +1,11 @@
export type TagKeys = "Contact" | "Company" | "Lead" | "Customer";
export type SelectedTags = Record<TagKeys, string[] | []>;
export type QuestionKeys = "Company" | "Lead" | "Customer";
export type SelectedQuestions = Record<QuestionKeys, string[] | []>;
export type minifiedData = {
id: string;
title: string;
subTitle?: string;
};

@ -0,0 +1,250 @@
import { FC, useEffect, useState } from "react";
import { enqueueSnackbar } from "notistack";
import type {
TagKeys,
SelectedTags,
QuestionKeys,
SelectedQuestions,
minifiedData,
} from "./types";
import {
AccountResponse,
getIntegrationRules,
getPipelines,
getSteps,
getTags,
getUsers,
getAccount,
} from "@/api/integration";
const SIZE = 25;
interface Props {
isModalOpen: boolean;
isTryRemoveAccount: boolean;
quizID: number;
}
export const useAmoIntegration = ({
isModalOpen,
isTryRemoveAccount,
quizID,
}: Props) => {
const [isloadingPage, setIsLoadingPage] = useState<boolean>(true);
const [firstRules, setFirstRules] = useState<boolean>(false);
const [accountInfo, setAccountInfo] = useState<AccountResponse | null>(null);
const [arrayOfPipelines, setArrayOfPipelines] = useState<minifiedData[]>([]);
const [arrayOfPipelinesSteps, setArrayOfPipelinesSteps] = useState<minifiedData[]>([]);
const [arrayOfUsers, setArrayOfUsers] = useState<minifiedData[]>([]);
const [arrayOfTags, setArrayOfTags] = useState<minifiedData[]>([]);
const [selectedPipeline, setSelectedPipeline] = useState<string | null>(null);
const [selectedPipelineStep, setSelectedPipelineStep] = useState<string | null>(null);
const [selectedDealUser, setSelectedDealPerformer] = useState<string | null>(null);
const [questionEntityBackend, setQuestionEntityBackend] = useState<Record<Partial<TagKeys>, number> | {}>({});
const [selectedTags, setSelectedTags] = useState<SelectedTags>({
Lead: [],
Contact: [],
Company: [],
Customer: [],
});
const [selectedQuestions, setSelectedQuestions] = useState<SelectedQuestions>({
Lead: [],
Company: [],
Customer: [],
});
const [pageOfPipelines, setPageOfPipelines] = useState(1);
const [pageOfPipelinesSteps, setPageOfPipelinesSteps] = useState(1);
const [pageOfUsers, setPageOfUsers] = useState(1);
const [pageOfTags, setPageOfTags] = useState(1);
useEffect(() => {
if (isModalOpen && !isTryRemoveAccount) {
const fetchAccountRules = async () => {
setIsLoadingPage(true)
const [account, accountError] = await getAccount();
if (accountError) {
if (!accountError.includes("Not Found")) enqueueSnackbar(accountError)
setAccountInfo(null);
}
if (account) {
setAccountInfo(account);
}
const [settingsResponse, rulesError] = await getIntegrationRules(quizID.toString());
if (rulesError) {
if (rulesError === "first") setFirstRules(true);
if (!rulesError.includes("Not Found") && !rulesError.includes("first")) enqueueSnackbar(rulesError);
}
if (settingsResponse) {
if (settingsResponse.PipelineID) setSelectedPipeline(settingsResponse.PipelineID.toString())
if (settingsResponse.StepID) setSelectedPipelineStep(settingsResponse.StepID.toString())
if (settingsResponse.PerformerID) setSelectedDealPerformer(settingsResponse.PerformerID.toString())
if (Boolean(settingsResponse.FieldsRule) &&
Object.keys(settingsResponse?.FieldsRule).length > 0) {
const gottenQuestions = { ...selectedQuestions }
setQuestionEntityBackend(settingsResponse.FieldsRule)
for (let key in settingsResponse.FieldsRule) {
if (settingsResponse.FieldsRule[key as QuestionKeys] !== null && Array.isArray(settingsResponse.FieldsRule[key as QuestionKeys])) {
const gottenList = settingsResponse.FieldsRule[key as QuestionKeys]
if (gottenList !== null)
gottenQuestions[key as QuestionKeys] = Object.keys(gottenList[0].QuestionID)
}
}
setSelectedQuestions(gottenQuestions)
}
if (Boolean(settingsResponse.TagsToAdd) &&
Object.keys(settingsResponse.TagsToAdd).length > 0) {
const gottenTags = { ...selectedTags }
for (let key in settingsResponse.TagsToAdd) {
const gottenList = settingsResponse.TagsToAdd[key as TagKeys]
if (gottenList !== null && Array.isArray(gottenList)) {
gottenTags[key as TagKeys] = gottenList.map(e => e.toString())
}
}
setSelectedTags(gottenTags)
}
setFirstRules(false);
}
setIsLoadingPage(false)
};
fetchAccountRules();
} else {
//Вот по-хорошему компонент должен размонтироваться и стереть всё. Но это будет сделано позже
setArrayOfPipelines([]);
setArrayOfPipelinesSteps([]);
setArrayOfUsers([]);
setArrayOfTags([]);
setSelectedPipeline(null);
setSelectedPipelineStep(null);
setSelectedDealPerformer(null);
setQuestionEntityBackend({});
setSelectedTags({
Lead: [],
Contact: [],
Company: [],
Customer: [],
});
setSelectedQuestions({
Lead: [],
Company: [],
Customer: [],
});
setPageOfPipelines(1);
setPageOfPipelinesSteps(1);
setPageOfUsers(1);
setPageOfTags(1);
}
}, [isModalOpen, isTryRemoveAccount]);
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]);
}
})
}, [pageOfPipelines])
useEffect(() => {
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((prevItems) => [...prevItems, ...minifiedSteps]);
}
});
}, [selectedPipeline, pageOfPipelinesSteps])
useEffect(() => {
getUsers({
page: pageOfUsers,
size: SIZE,
}).then(([response]) => {
if (response && response.items !== null) {
const minifiedUsers: minifiedData[] = []
response.items.forEach((step) => {
minifiedUsers.push({
id: step.amoID.toString(),
title: step.name
})
})
setArrayOfUsers((prevItems) => [...prevItems, ...minifiedUsers]);
}
});
}, [pageOfUsers])
useEffect(() => {
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
})
})
setArrayOfTags((prevItems) => [...prevItems, ...minifiedTags]);
}
});
}, [pageOfTags])
return ({
isloadingPage,
firstRules,
accountInfo,
arrayOfPipelines,
arrayOfPipelinesSteps,
arrayOfUsers,
arrayOfTags,
selectedPipeline,
setSelectedPipeline,
selectedPipelineStep,
setSelectedPipelineStep,
selectedDealUser,
setSelectedDealPerformer,
questionEntityBackend,
selectedTags,
setSelectedTags,
selectedQuestions,
setSelectedQuestions,
setPageOfPipelines,
setPageOfPipelinesSteps,
setPageOfUsers,
setPageOfTags,
})
}