diff --git a/src/components/AmoButton/AmoButton.tsx b/src/components/AmoButton/AmoButton.tsx index 0c04b643..b6f93c2f 100644 --- a/src/components/AmoButton/AmoButton.tsx +++ b/src/components/AmoButton/AmoButton.tsx @@ -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 = { diff --git a/src/components/CustomRadioGroup/CustomRadioGroup.tsx b/src/components/CustomRadioGroup/CustomRadioGroup.tsx index b64c056b..1df2888a 100644 --- a/src/components/CustomRadioGroup/CustomRadioGroup.tsx +++ b/src/components/CustomRadioGroup/CustomRadioGroup.tsx @@ -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 = ({ return item.entity === activeScope; }) : items - const onScroll = React.useCallback((e: React.UIEvent) => { - 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 = ({ return ( 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 = ({ name="controlled-radio-buttons-group" value={selectedItemId} onChange={({ target }: SelectChangeEvent) => setSelectedItem(target.value)} - onScroll={onScroll} > {formControlLabels} diff --git a/src/components/CustomSelect/CustomSelect.tsx b/src/components/CustomSelect/CustomSelect.tsx index 15fd7e0c..e7426d6e 100644 --- a/src/components/CustomSelect/CustomSelect.tsx +++ b/src/components/CustomSelect/CustomSelect.tsx @@ -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 = ({ items, selectedItemId, set setOpened((isOpened) => !isOpened); }, []); - const onScroll = useCallback((e: React.UIEvent) => { - 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 = ({ 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 = ({ items, selectedItemId, set нет данных @@ -93,10 +84,10 @@ export const CustomSelect: FC = ({ items, selectedItemId, set }, [items, selectedItemId]); return ( - + = ({ 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 = ({ items, selectedItemId, set border: 0, }, "& .MuiMenu-root.MuiModal-root": { - zIndex: 0, + zIndex: 2, }, }} onChange={({ target }: SelectChangeEvent) => setSelectedItem(target.value)} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AccountInfo.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/AccountInfo.tsx new file mode 100644 index 00000000..51a22712 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/AccountInfo.tsx @@ -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 = ({ handleNextStep, accountInfo, toChangeAccount }) => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + + const infoItem = (title: string, value: string | number | undefined) => ( + + + {title}: + + + {value || "нет данных"} + + + ); + + const infoItemLink = (title: string, link: string | undefined) => ( + + + {title}: + + + { + link ? + + {link} + + : + не указана + } + + + ); + + return ( + + + + + Информация об аккаунте + + + 1 шаг + + {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)} + + + + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoAccountInfo/AmoAccountInfo.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoAccountInfo/AmoAccountInfo.tsx deleted file mode 100644 index e6b00856..00000000 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoAccountInfo/AmoAccountInfo.tsx +++ /dev/null @@ -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 = ({ handleNextStep, accountInfo }) => { - const theme = useTheme(); - const isMobile = useMediaQuery(theme.breakpoints.down(600)); - - const infoItem = (title: string, value: string | number) => ( - - - {title}: - - - {value || "нет данных"} - - - ); - - const infoItemLink = (title: string, link: string) => ( - - - {title}: - - - - {link} - - - - ); - - return ( - - - {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)} - - - - ); -}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoCRMModal.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoCRMModal.tsx deleted file mode 100644 index 5283576f..00000000 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoCRMModal.tsx +++ /dev/null @@ -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 = ({ 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(0); - const [isSettingsBlock, setIsSettingsBlock] = useState(false); - const [isTryRemoveAccount, setIsTryRemoveAccount] = useState(false); - const [openDelete, setOpenDelete] = useState(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 ? ( - - ) : ( - - ), - }, - { - title: "Выбор воронки", - isSettingsAvailable: true, - component: ( - - ), - }, - { - title: "Выбор этапа воронки", - isSettingsAvailable: true, - component: ( - - ), - }, - { - title: "Сделка", - isSettingsAvailable: true, - component: ( - - ), - }, - { - title: "Добавление тегов", - isSettingsAvailable: true, - component: ( - { }} - handleAddTag={handleAddTagQuestion} - handlePrevStep={handlePrevStep} - handleNextStep={handleNextStep} - /> - ), - }, - { - title: "Соотнесение вопросов и сущностей", - isSettingsAvailable: true, - component: ( - - ), - }, - ], - [ - arrayOfPipelines, - arrayOfPipelinesSteps, - arrayOfUsers, - arrayOfTags, - arrayOfFields, - selectedPipeline, - selectedPipelineStep, - selectedDealUser, - selectedQuestions, - selectedTags, - arrayOfPipelines, - arrayOfPipelinesSteps, - arrayOfUsers, - minifiedQuestions, - selectedCurrentFields, - ] - ); - - const stepTitles = steps.map((step) => step.title); - - return ( - - - - Интеграция с {companyName ? companyName : "партнером"} - - - - - - - {isLoadingPage ? - : - <> - setIsTryRemoveAccount(true)} - /> - {openDelete !== null ? ( - setOpenDelete(null)} - deleteItem={handleDeleteTagQuestion} - /> - ) : ( - <> - {isTryRemoveAccount && setIsTryRemoveAccount(false)} />} - {isSettingsBlock && ( - - u.id === selectedDealUser)?.title || "не указан"} - selectedFunnel={arrayOfPipelines.find((p) => p.id === selectedPipeline)?.title || "нет данных"} - selectedStage={ - arrayOfPipelinesSteps.find((s) => s.id === selectedPipelineStep)?.title || "нет данных" - } - selectedQuestions={selectedQuestions} - selectedTags={selectedTags} - /> - - )} - {!isSettingsBlock && !isTryRemoveAccount && ( - {steps[step].component} - )} - - )} - - } - - - - - ); -}; - -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)); -} \ No newline at end of file diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoLogin/AmoLogin.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoLogin.tsx similarity index 98% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoLogin/AmoLogin.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoLogin.tsx index 92bf2ec4..7772f82a 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoLogin/AmoLogin.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoLogin.tsx @@ -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 = { diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoTags/AmoTags.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoTags/AmoTags.tsx deleted file mode 100644 index e02bcdaf..00000000 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoTags/AmoTags.tsx +++ /dev/null @@ -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 = ({ - tagsItems, - selectedTags, - handleAddTag, - openDelete, - handleScroll, - handlePrevStep, - handleNextStep, -}) => { - const [sortedTagsItems, setSortedTagsItems] = useState(tagsItems); - - const [isSelection, setIsSelection] = useState(false); - const [activeScope, setActiveScope] = useState(null); - const [selectedTag, setSelectedTag] = useState(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 ( - - {isSelection && activeScope !== null ? ( - // Здесь выбираем элемент в табличку - <> - - { - setActiveScope(null); - setIsSelection(false); - }} - onLargeBtnClick={() => { - handleAdd(); - setActiveScope(null); - setIsSelection(false); - }} - /> - - ) : ( - // Табличка - - )} - - ); -}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AnswerItem.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/AnswerItem.tsx new file mode 100644 index 00000000..a237cd7c --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/AnswerItem.tsx @@ -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 = ({ fieldName, fieldValue, deleteHC }) => { + console.log("AnswerItem") + console.log(fieldName) + const theme = useTheme(); + return ( + + + + {fieldName} + + + + {fieldValue} + + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/DealPerformers/DealPerformers.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/DealPerformers.tsx similarity index 68% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/DealPerformers/DealPerformers.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/DealPerformers.tsx index 43198363..9ffe4c98 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/DealPerformers/DealPerformers.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/DealPerformers.tsx @@ -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 = ({ @@ -18,27 +27,34 @@ export const DealPerformers: FC = ({ handleNextStep, selectedDealUser, setSelectedDealPerformer, + onScrollUsers, + titleProps, }) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isTablet = useMediaQuery(theme.breakpoints.down(1000)); return ( + <> - + + {}} + handleScroll={onScrollUsers} /> = ({ /> + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoRemoveAccount/AmoDeleteTagQuestion.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/DeleteTagQuestion.tsx similarity index 92% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoRemoveAccount/AmoDeleteTagQuestion.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/DeleteTagQuestion.tsx index 315251e0..0ac9ec1a 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoRemoveAccount/AmoDeleteTagQuestion.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/DeleteTagQuestion.tsx @@ -6,7 +6,7 @@ interface Props { close: () => void; } -export const AmoDeleteTagQuestion: FC = ({ close, deleteItem }) => { +export const DeleteTagQuestion: FC = ({ close, deleteItem }) => { const theme = useTheme(); return ( diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoModalTitle/AmoModalTitle.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/ModalTitle.tsx similarity index 51% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoModalTitle/AmoModalTitle.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/ModalTitle.tsx index c429ad37..6988f44b 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoModalTitle/AmoModalTitle.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/ModalTitle.tsx @@ -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 = ({ +export const ModalTitle: FC = ({ 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 ( - + - {isSettingsBlock ? "Мои настройки" : steps[step].title} + {title} - {isSettingsBlock || ( + { + desc && - Шаг {step + 1} + {desc} - )} + } + + {step} шаг + - {steps[step].isSettingsAvailable && ( + + + - )} + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/PipelineSteps.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/PipelineSteps.tsx new file mode 100644 index 00000000..29d62ba0 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/PipelineSteps.tsx @@ -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 = ({ + 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 ( + <> + + + + + + + + + + + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/PipelineSteps/PipelineSteps.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/PipelineSteps/PipelineSteps.tsx deleted file mode 100644 index 3a7b55fc..00000000 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/PipelineSteps/PipelineSteps.tsx +++ /dev/null @@ -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 = ({ - 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 ( - - - {}} - /> - - - {}} - /> - - - - - - ); -}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/Pipelines.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Pipelines.tsx new file mode 100644 index 00000000..21604793 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Pipelines.tsx @@ -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 = ({ + 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 ( + <> + + + + + + + + + + + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/Pipelines/Pipelines.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Pipelines/Pipelines.tsx deleted file mode 100644 index 46026217..00000000 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/Pipelines/Pipelines.tsx +++ /dev/null @@ -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 = ({ - 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 ( - - - {}} - /> - - - {}} - /> - - - - - - ); -}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/AmoQuestions.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/AmoQuestions.tsx similarity index 59% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/AmoQuestions.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/AmoQuestions.tsx index 697a4e8e..cdba06c8 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/AmoQuestions.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/AmoQuestions.tsx @@ -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 = ({ handleNextStep, openDelete, FieldsAllowedFC, - setSelectedCurrentFields + setSelectedCurrentFields, + onScroll, + titleProps, }) => { const [isSelection, setIsSelection] = useState(false); const [activeScope, setActiveScope] = useState(null); @@ -109,17 +119,6 @@ export const AmoQuestions: FC = ({ const [sortedFieldsItems, setSortedFieldsItems] = useState(fieldsItems); const [sortedquestionsItems, setSortedquestionsItems] = useState(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 = ({ setSortedquestionsItems(questionsItems); }, [activeScope]) return ( - - {isSelection && activeScope !== null ? ( - <> - + <> + + + + {isSelection && activeScope !== null ? ( + // Здесь выбираем элемент в табличку + <> + + + + ) : ( + // Табличка + + )} + + - {/* табличка */} - - { - setActiveScope(null); - setIsSelection(false); - }} + + {isSelection && activeScope !== null ? + { handleAdd(); setActiveScope(null); setIsSelection(false); }} - activeScope={activeScope} - setIsCurrentFields={setIsCurrentFields} - isCurrentFields={isCurrentFields} + largeBtnText={"Добавить"} + onSmallBtnClick={() => { + setActiveScope(null); + setIsSelection(false); + }} + smallBtnText={"Отменить"} /> - - // Здесь выбираем элемент в табличку - // { - // setActiveScope(null); - // setIsSelection(false); - // }} - // onLargeBtnClick={() => { - // handleAdd(); - // setActiveScope(null); - // setIsSelection(false); - // }} - // /> - ) : ( - // Табличка - - )} - + : + + + } + + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/CurrentFieldSelectMobile.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/CurrentFieldSelectMobile.tsx similarity index 100% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/CurrentFieldSelectMobile.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/CurrentFieldSelectMobile.tsx diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/CurrentFields.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/CurrentFields.tsx similarity index 63% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/CurrentFields.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/CurrentFields.tsx index 2f75ae5a..23430a64 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/CurrentFields.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/CurrentFields.tsx @@ -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 && { }}/> + selectedItemId={currentField} + setSelectedItem={setCurrentField} + handleScroll={handleScroll} /> } {!isMobile && - { }} - activeScope={undefined} - /> + } @@ -85,20 +87,20 @@ export const CurrentFields = ({ }} >Выберите вопрос для этого поля {isMobile && - { }}/> + { }} /> } {!isMobile && - { }} - activeScope={undefined} - /> + { }} + activeScope={undefined} + /> } diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/EntitiesQuestions.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/EntitiesQuestions.tsx similarity index 79% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/EntitiesQuestions.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/EntitiesQuestions.tsx index 673bce17..8a9b7ed5 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/EntitiesQuestions.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/EntitiesQuestions.tsx @@ -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 = ({ selectedField, setSelectedField, handleScroll, - onLargeBtnClick, - onSmallBtnClick, activeScope, FieldsAllowedFC, selectedCurrentFields, @@ -41,13 +37,6 @@ export const EntitiesQuestions: FC = ({ }) => { 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 ( = ({ currentQuestion={selectedItemId} setCurrentField={setSelectedField} setCurrentQuestion={setSelectedQuestion} + handleScroll={handleScroll} /> : = ({ /> } - - { - onLargeBtnClick() - }} - largeBtnText={"Добавить"} - onSmallBtnClick={onSmallBtnClick} - smallBtnText={"Отменить"} - /> - ) } \ No newline at end of file diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/Item/AnswerItem/AnswerItem.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/Item/AnswerItem/AnswerItem.tsx similarity index 100% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/Item/AnswerItem/AnswerItem.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/Item/AnswerItem/AnswerItem.tsx diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/Item/IconBtnAdd/IconBtnAdd.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/Item/IconBtnAdd/IconBtnAdd.tsx similarity index 100% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/Item/IconBtnAdd/IconBtnAdd.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/Item/IconBtnAdd/IconBtnAdd.tsx diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/Item/Item.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/Item/Item.tsx similarity index 100% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/Item/Item.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/Item/Item.tsx diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/ItemDetailsView/ItemDetailsView.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/ItemDetailsView/ItemDetailsView.tsx similarity index 79% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/ItemDetailsView/ItemDetailsView.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/ItemDetailsView/ItemDetailsView.tsx index 86e6c10d..23ab2914 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/ItemDetailsView/ItemDetailsView.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/ItemDetailsView/ItemDetailsView.tsx @@ -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 = ({ items, - handleSmallBtn, - handleLargeBtn, selectedQuestions, setIsSelection, setActiveScope, @@ -68,18 +64,6 @@ export const ItemDetailsView: FC = ({ ))} - - - ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/ItemForQuestions.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/ItemForQuestions.tsx similarity index 100% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/ItemForQuestions.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/ItemForQuestions.tsx diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/ItemsSelectionView/ItemsSelectionView.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/ItemsSelectionView/ItemsSelectionView.tsx similarity index 69% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/ItemsSelectionView/ItemsSelectionView.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/ItemsSelectionView/ItemsSelectionView.tsx index 6a135e2a..f1c0a36f 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/ItemsSelectionView/ItemsSelectionView.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/ItemsSelectionView/ItemsSelectionView.tsx @@ -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 = ({ selectedItemId, setSelectedItem, handleScroll, - onLargeBtnClick, - onSmallBtnClick, activeScope, }) => { return ( @@ -49,19 +45,6 @@ export const ItemsSelectionView: FC = ({ activeScope={activeScope} /> - - - ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/NewFields.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/NewFields.tsx similarity index 100% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoQuestions/NewFields.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/NewFields.tsx diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoRemoveAccount/AmoRemoveAccount.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/RemoveAccount.tsx similarity index 97% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoRemoveAccount/AmoRemoveAccount.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/RemoveAccount.tsx index 381a43b9..ca96975b 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoRemoveAccount/AmoRemoveAccount.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/RemoveAccount.tsx @@ -10,7 +10,7 @@ interface Props { } -export const AmoRemoveAccount: FC = ({ +export const RemoveAccount: FC = ({ stopThisPage, handleCloseModal, diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/SettingsBlock/AmoSettingsBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/SettingsBlock/AmoSettingsBlock.tsx deleted file mode 100644 index 4d5fc8e4..00000000 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/SettingsBlock/AmoSettingsBlock.tsx +++ /dev/null @@ -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 = ({ - stepTitles, - setStep, - setIsSettingsBlock, - selectedFunnel, - selectedDealUser, - selectedStage, - selectedQuestions, - selectedTags, -}) => { - const theme = useTheme(); - const isMobile = useMediaQuery(theme.breakpoints.down(600)); - - return ( - - - {stepTitles && - stepTitles.map((title, index) => ( - - ))} - - - setIsSettingsBlock(false)} - isLargeBtnMissing={true} - /> - - - ); -}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/SettingsBlock/SettingItem/SettingItem.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/SettingsBlock/SettingItem/SettingItem.tsx index ee1614be..ce9cf851 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/SettingsBlock/SettingItem/SettingItem.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/SettingsBlock/SettingItem/SettingItem.tsx @@ -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 = ({ step, title, setStep, - setIsSettingsBlock, selectedFunnelPerformer, selectedFunnel, selectedStagePerformer, @@ -34,6 +32,7 @@ export const SettingItem: FC = ({ 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 = ({ setStep(step)} /> {SettingsContent} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/SettingsBlock/SettingItem/SettingItemHeader/SettingItemHeader.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/SettingsBlock/SettingItem/SettingItemHeader/SettingItemHeader.tsx index 61a43ea2..bbf6d11a 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/SettingsBlock/SettingItem/SettingItemHeader/SettingItemHeader.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/SettingsBlock/SettingItem/SettingItemHeader/SettingItemHeader.tsx @@ -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 = ({ title, step, setStep, - setIsSettingsBlock, }) => { const theme = useTheme(); - const handleClick = () => { - setStep(step); - setIsSettingsBlock(false); - }; - return ( = ({ > {step} этап - + void + setStep: (step: number) => void +}; + +export const SettingsBlock: FC = ({ + stepTitles, + selectedFunnel, + selectedDealUser, + selectedStage, + selectedQuestions, + selectedTags, + toBack, + setStep, +}) => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + + return ( + + + + Мои настройки + + + {stepTitles && + stepTitles.map((title, index) => ( + + ))} + + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/StepButtonsBlock/StepButtonsBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/StepButtonsBlock.tsx similarity index 96% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/StepButtonsBlock/StepButtonsBlock.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/StepButtonsBlock.tsx index d829f09a..94a80e81 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/StepButtonsBlock/StepButtonsBlock.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/StepButtonsBlock.tsx @@ -30,9 +30,10 @@ export const StepButtonsBlock: FC = ({ {isSmallBtnMissing || ( diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/SwitchPages.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/SwitchPages.tsx new file mode 100644 index 00000000..ab8cb5e4 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/SwitchPages.tsx @@ -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(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: ( + 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: ( + setSpecialPage("settingsBlock") + }} + onScroll={setPageOfPipelinesSteps} + onScrollUsers={setPageOfUsers} + /> + ), + }, + { + isSettingsAvailable: true, + component: ( + setSpecialPage("settingsBlock") + }} + onScrollUsers={setPageOfUsers} + /> + ), + }, + { + isSettingsAvailable: true, + component: ( + setSpecialPage("settingsBlock") + }} + onScroll={setPageOfTags} + /> + ), + }, + { + isSettingsAvailable: true, + component: ( + setSpecialPage("settingsBlock") + }} + onScroll={setPageOfFields} + /> + ), + }, + ] + + const stepTitles = steps.map((step) => step.title); + + switch (specialPage) { + case "deleteCell": + return + case "removeAccount": + return + case "settingsBlock": + return 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 + case "accountInfo": return closeSpecialPage()} + accountInfo={accountInfo} + toChangeAccount={() => setSpecialPage("removeAccount")} + /> + + + default: return {steps[step].component} + } +} \ No newline at end of file diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/Tags/AmoTags.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Tags/AmoTags.tsx new file mode 100644 index 00000000..3e254618 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Tags/AmoTags.tsx @@ -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 = ({ + tagsItems, + selectedTags, + handleAddTag, + openDelete, + handlePrevStep, + handleNextStep, + onScroll, + titleProps, +}) => { + const [sortedTagsItems, setSortedTagsItems] = useState(tagsItems); + + const [isSelection, setIsSelection] = useState(false); + const [activeScope, setActiveScope] = useState(null); + const [selectedTag, setSelectedTag] = useState(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 ( + <> + + + + {isSelection && activeScope !== null ? ( + // Здесь выбираем элемент в табличку + <> + + + + ) : ( + // Табличка + + )} + + + + + { + isSelection && activeScope !== null ? + { + handleAdd(); + setActiveScope(null); + setIsSelection(false); + }} + largeBtnText={"Добавить"} + onSmallBtnClick={() => { + setActiveScope(null); + setIsSelection(false); + }} + smallBtnText={"Отменить"} + /> + : + + } + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoTags/TagsDetailsView/TagsDetailsView.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Tags/TagsDetailsView/TagsDetailsView.tsx similarity index 81% rename from src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoTags/TagsDetailsView/TagsDetailsView.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Amo/Tags/TagsDetailsView/TagsDetailsView.tsx index 398c42e8..61499c08 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/AmoTags/TagsDetailsView/TagsDetailsView.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/Tags/TagsDetailsView/TagsDetailsView.tsx @@ -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 = ({ setActiveScope, selectedTags, setIsSelection, - handlePrevStep, - handleNextStep, deleteHC, }) => { const theme = useTheme(); @@ -30,7 +26,7 @@ export const TagsDetailsView: FC = ({ return ( = ({ = ({ ))} - - - ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/index.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Amo/index.tsx new file mode 100644 index 00000000..3ef074bb --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/index.tsx @@ -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 = ({ 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(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 ( + + + + + Интеграция с {companyName ? companyName : "партнером"} + + + + + + + + {isLoadingPage ? + : + + } + + + ); +}; + +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)); +} \ No newline at end of file diff --git a/src/pages/IntegrationsPage/IntegrationsModal/Amo/useAmoIntegration.ts b/src/pages/IntegrationsPage/IntegrationsModal/Amo/useAmoIntegration.ts index d4c0a477..d63bd3bd 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/Amo/useAmoIntegration.ts +++ b/src/pages/IntegrationsPage/IntegrationsModal/Amo/useAmoIntegration.ts @@ -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(true); const [firstRules, setFirstRules] = useState(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, }; }; diff --git a/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx b/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx index 9834371e..48983487 100644 --- a/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx +++ b/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx @@ -16,7 +16,7 @@ const AnalyticsModal = lazy(() => ); const AmoCRMModal = lazy(() => - import("../IntegrationsModal/Amo/AmoCRMModal").then((module) => ({ + import("../IntegrationsModal/Amo").then((module) => ({ default: module.AmoCRMModal, })) ); diff --git a/src/utils/throttle.ts b/src/utils/throttle.ts new file mode 100644 index 00000000..61627cbd --- /dev/null +++ b/src/utils/throttle.ts @@ -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(); + } +} diff --git a/yarn.lock b/yarn.lock index c23cb60c..c26b3a91 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"