diff --git a/src/api/integration.ts b/src/api/integration.ts index 7d59a3f4..5236c2d6 100644 --- a/src/api/integration.ts +++ b/src/api/integration.ts @@ -21,7 +21,7 @@ export type TagsResponse = { count: number; items: Tag[]; }; -const API_URL = `${process.env.REACT_APP_DOMAIN}/squiz/amocrm/amocrm`; +const API_URL = `${process.env.REACT_APP_DOMAIN}/squiz/amocrm`; export const getTags = async ({ page, @@ -112,3 +112,37 @@ export const getSteps = async ({ return [null, `Не удалось получить список шагов. ${error}`]; } }; + +export type Pipeline = { + ID: number; + AmoID: number; + AccountID: number; + Name: string; + IsArchive: boolean; + Deleted: boolean; + CreatedAt: number; +}; + +export type PipelinesResponse = { + count: number; + items: Pipeline[]; +}; + +export const getPipelines = async ({ + page, + size, +}: PaginationRequest): Promise<[PipelinesResponse | null, string?]> => { + try { + const pipelinesResponse = await makeRequest< + PaginationRequest, + PipelinesResponse + >({ + method: "GET", + url: `${API_URL}/pipelines?page=${page}&size=${size}`, + }); + return [pipelinesResponse]; + } catch (nativeError) { + const [error] = parseAxiosError(nativeError); + return [null, `Не удалось получить список воронок. ${error}`]; + } +}; diff --git a/src/components/CustomRadioGroup/CustomRadioGroup.tsx b/src/components/CustomRadioGroup/CustomRadioGroup.tsx index f70395c1..e83d8071 100644 --- a/src/components/CustomRadioGroup/CustomRadioGroup.tsx +++ b/src/components/CustomRadioGroup/CustomRadioGroup.tsx @@ -7,9 +7,11 @@ import Box from "@mui/material/Box"; import CheckboxIcon from "@icons/Checkbox"; import { Typography, useTheme } from "@mui/material"; import { + getPipelines, getSteps, getTags, PaginationRequest, + Pipeline, Step, Tag, } from "@api/integration"; @@ -37,6 +39,7 @@ export const CustomRadioGroup: FC = ({ const [isLoading, setIsLoading] = useState(false); const [tags, setTags] = useState([]); const [steps, setSteps] = useState([]); + const [pipelines, setPipelines] = useState([]); const [hasMoreItems, setHasMoreItems] = useState(true); const boxRef = useRef(null); @@ -90,6 +93,22 @@ export const CustomRadioGroup: FC = ({ 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(() => { @@ -123,7 +142,6 @@ export const CustomRadioGroup: FC = ({ icon={} /> } - // label={item.Name} label={ @@ -171,6 +189,41 @@ export const CustomRadioGroup: FC = ({ /> )); } + if (type === "typePipelines" && pipelines && pipelines.length !== 0) { + return pipelines.map((pipeline) => ( + + } + icon={} + /> + } + label={pipeline.Name} + labelPlacement={"start"} + /> + )); + } return ( = ({ Нет элементов ); - }, [tags, currentValue, type]); + }, [tags, steps, currentValue, type, pipelines]); return ( = ({ const [hasMoreItems, setHasMoreItems] = useState(true); const SIZE = 25; const ref = useRef(null); - console.log("page", page); + const selectWidth = ref.current ? ref.current.offsetWidth : undefined; + + const [savedValue, setSavedValue] = useState(null); const onSelectItem = useCallback( (event: SelectChangeEvent) => { const newValue = event.target.value.toString(); + const selectedUser = users.find((user) => user.Name === newValue); + if (selectedUser) { + //для сохранения ID выбранного пользователя в стейт или конфиг... + setSavedValue(selectedUser.ID); + } setCurrentValue(newValue); setSelectedItem(newValue); }, - [setSelectedItem, setCurrentValue], + [setSelectedItem, setCurrentValue, setSavedValue, users], ); const toggleOpened = useCallback(() => { @@ -86,9 +93,56 @@ export const CustomSelect: FC = ({ - {user.Name} + + + {user.Name} + + + {user.Email} + + + {user.Role} + + )); } @@ -162,10 +216,12 @@ export const CustomSelect: FC = ({ zIndex: 2, maxHeight: "300px", overflow: "auto", + overflowX: "auto", + maxWidth: selectWidth, }, }, }} - sx={{ width: "100%" }} + sx={{}} onChange={onSelectItem} onClick={toggleOpened} > diff --git a/src/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal.tsx index dc924892..330b5f61 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal.tsx @@ -12,9 +12,8 @@ import { IntegrationStep1 } from "./IntegrationStep1/IntegrationStep1"; import { IntegrationStep2 } from "./IntegrationStep2/IntegrationStep2"; import { IntegrationStep3 } from "./IntegrationStep3/IntegrationStep3"; import { IntegrationStep4 } from "./IntegrationStep4/IntegrationStep4"; -import { IntegrationStep5 } from "./IntegrationStep5/IntegrationStep5"; import { IntegrationStep6 } from "./IntegrationStep6/IntegrationStep6"; -import { funnelsMock, performersMock, stagesMock } from "../mocks/MockData"; +import { performersMock } from "../mocks/MockData"; import { IntegrationsModalTitle } from "./IntegrationsModalTitle/IntegrationsModalTitle"; import { SettingsBlock } from "./SettingsBlock/SettingsBlock"; import { IntegrationStep7 } from "./IntegrationStep7/IntegrationStep7"; @@ -42,18 +41,17 @@ export const AmoCRMModal: FC = ({ const [step, setStep] = useState(0); const [isSettingsBlock, setIsSettingsBlock] = useState(false); - const [selectedFunnelPerformer, setSelectedFunnelPerformer] = useState< + const [selectedPipelinePerformer, setSelectedPipelinePerformer] = useState< string | null >(null); - const [selectedFunnel, setSelectedFunnel] = useState(null); - const [selectedStagePerformer, setSelectedStagePerformer] = useState< + const [selectedPipeline, setSelectedPipeline] = useState(null); + const [selectedStepsPerformer, setSelectedStepsPerformer] = useState< string | null >(null); - const [selectedStage, setSelectedStage] = useState(null); + const [selectedStep, setSelectedStep] = useState(null); const [selectedDealPerformer, setSelectedDealPerformer] = useState< string | null >(null); - const [utmFile, setUtmFile] = useState(null); const [questionEntity, setQuestionEntity] = useState({ contacts: [], company: [], @@ -93,12 +91,10 @@ export const AmoCRMModal: FC = ({ ), }, @@ -109,13 +105,11 @@ export const AmoCRMModal: FC = ({ ), }, @@ -132,18 +126,6 @@ export const AmoCRMModal: FC = ({ /> ), }, - { - title: "Добавление utm-меток", - isSettingsAvailable: false, - component: ( - - ), - }, { title: "Соотнесение вопросов и сущностей", isSettingsAvailable: true, @@ -171,11 +153,11 @@ export const AmoCRMModal: FC = ({ ], [ questionEntity, - utmFile, - selectedFunnelPerformer, - selectedFunnel, - selectedStagePerformer, - selectedStage, + // utmFile, + selectedPipelinePerformer, + selectedPipeline, + selectedStepsPerformer, + selectedStep, selectedDealPerformer, tags, ], @@ -188,7 +170,7 @@ export const AmoCRMModal: FC = ({ open={isModalOpen} onClose={handleCloseModal} fullWidth - fullScreen={isMobile} + // fullScreen={isMobile} PaperProps={{ sx: { maxWidth: isTablet ? "100%" : "920px", @@ -253,11 +235,10 @@ export const AmoCRMModal: FC = ({ setIsSettingsBlock={setIsSettingsBlock} setStep={setStep} selectedDealPerformer={selectedDealPerformer} - selectedFunnelPerformer={selectedFunnelPerformer} - selectedFunnel={selectedFunnel} - selectedStagePerformer={selectedStagePerformer} - selectedStage={selectedStage} - utmFile={utmFile} + selectedFunnelPerformer={selectedPipelinePerformer} + selectedFunnel={selectedPipeline} + selectedStagePerformer={selectedStepsPerformer} + selectedStage={selectedStep} questionEntity={questionEntity} tags={tags} /> diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep2/IntegrationStep2.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep2/IntegrationStep2.tsx index 129dd95e..dd055bbf 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep2/IntegrationStep2.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep2/IntegrationStep2.tsx @@ -7,23 +7,19 @@ import { CustomRadioGroup } from "../../../../components/CustomRadioGroup/Custom type IntegrationStep2Props = { handlePrevStep: () => void; handleNextStep: () => void; - selectedFunnelPerformer: string | null; - setSelectedFunnelPerformer: (value: string | null) => void; - selectedFunnel: string | null; - setSelectedFunnel: (value: string | null) => void; - performers: string[]; - funnels: string[]; + selectedPipelinePerformer: string | null; + setSelectedPipelinePerformer: (value: string | null) => void; + selectedPipeline: string | null; + setSelectedPipeline: (value: string | null) => void; }; export const IntegrationStep2: FC = ({ handlePrevStep, handleNextStep, - selectedFunnelPerformer, - setSelectedFunnelPerformer, - selectedFunnel, - setSelectedFunnel, - performers, - funnels, + selectedPipelinePerformer, + setSelectedPipelinePerformer, + selectedPipeline, + setSelectedPipeline, }) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); @@ -40,8 +36,8 @@ export const IntegrationStep2: FC = ({ > @@ -54,8 +50,9 @@ export const IntegrationStep2: FC = ({ }} > void; handleNextStep: () => void; - selectedStagePerformer: string | null; - setSelectedStagePerformer: (value: string | null) => void; - selectedStage: string | null; - setSelectedStage: (value: string | null) => void; - performers: string[]; - stages: string[]; + selectedStepsPerformer: string | null; + setSelectedStepsPerformer: (value: string | null) => void; + selectedStep: string | null; + setSelectedStep: (value: string | null) => void; pipelineId: string | null; }; export const IntegrationStep3: FC = ({ handlePrevStep, handleNextStep, - selectedStagePerformer, - setSelectedStagePerformer, - selectedStage, - setSelectedStage, + selectedStepsPerformer, + setSelectedStepsPerformer, + selectedStep, + setSelectedStep, pipelineId, }) => { const theme = useTheme(); @@ -41,9 +39,9 @@ export const IntegrationStep3: FC = ({ > = ({ void; -} - -export const CustomFileUploader: FC = ({ - accept, - description, - handleImageChange, -}) => { - const theme = useTheme(); - const dropZone = useRef(null); - const [ready, setReady] = useState(false); - const isMobile = useMediaQuery(theme.breakpoints.down(700)); - - const handleDragEnter = (event: DragEvent) => { - event.preventDefault(); - setReady(true); - }; - - const handleDrop = (event: DragEvent) => { - event.preventDefault(); - event.stopPropagation(); - - const file = event.dataTransfer.files[0]; - if (!file) return; - - handleImageChange(file); - }; - - const acceptedFormats = accept - ? accept.map((format) => "." + format).join(", ") - : ""; - - return ( - - { - const file = event.target.files?.[0]; - if (file) handleImageChange(file); - }} - hidden - accept={acceptedFormats || ".jpg, .jpeg, .png , .gif"} - multiple - type="file" - data-cy="upload-image-input" - /> - ) => - event.preventDefault() - } - onDrop={handleDrop} - ref={dropZone} - sx={{ - width: isMobile ? "100%" : "580px", - padding: isMobile ? "33px" : "33px 10px 33px 55px", - display: "flex", - alignItems: "center", - backgroundColor: theme.palette.background.default, - border: `1px solid ${ready ? "red" : theme.palette.grey2.main}`, - borderRadius: "8px", - gap: "55px", - flexDirection: isMobile ? "column" : "row", - }} - onDragEnter={handleDragEnter} - > - - - - Добавить файл - - - {description || "Принимает JPG, PNG, и GIF формат — максимум 5mb"} - - - - - ); -}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/FileBlock/FileBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/FileBlock/FileBlock.tsx deleted file mode 100644 index 89d63fcf..00000000 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/FileBlock/FileBlock.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import React, { FC } from "react"; -import Box from "@mui/material/Box"; -import { IconButton, Typography, useTheme } from "@mui/material"; -import CloseIcon from "@mui/icons-material/Close"; - -type FileBlockProps = { - file: File | null; - setFile?: (file: File | null) => void; -}; - -export const FileBlock: FC = ({ setFile, file }) => { - const theme = useTheme(); - return ( - - - Вы загрузили: - - - - {file?.name} - - {setFile && ( - setFile(null)} - sx={{ - backgroundColor: "#864BD9", - borderRadius: "50%", - width: "24px", - height: "24px", - color: "white", - }} - > - - - )} - - - ); -}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx deleted file mode 100644 index dd5a60c1..00000000 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { Box, useMediaQuery, useTheme } from "@mui/material"; -import React, { FC } from "react"; -import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; -import File from "@ui_kit/QuizPreview/QuizPreviewQuestionTypes/File"; -import { FileBlock } from "./FileBlock/FileBlock"; -import { CustomFileUploader } from "./CustomFileUploader/CustomFileUploader"; - -type IntegrationStep5Props = { - handlePrevStep: () => void; - handleNextStep: () => void; - setUtmFile: (file: File | null) => void; - utmFile: File | null; -}; - -export const IntegrationStep5: FC = ({ - handlePrevStep, - handleNextStep, - utmFile, - setUtmFile, -}) => { - const theme = useTheme(); - const upMd = useMediaQuery(theme.breakpoints.up("md")); - - return ( - - - {utmFile ? ( - - ) : ( - - )} - - - - ); -}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx index bad4f702..82f0ac12 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx @@ -4,7 +4,6 @@ import { Typography, useMediaQuery, useTheme } from "@mui/material"; import { SettingItemHeader } from "./SettingItemHeader/SettingItemHeader"; import { ResponsiblePerson } from "./ResponsiblePerson/ResponsiblePerson"; import { SelectedParameter } from "./SelectedParameter/SelectedParameter"; -import { FileBlock } from "../../IntegrationStep5/FileBlock/FileBlock"; import { TQuestionEntity, TTags } from "../../AmoCRMModal"; type SettingItemProps = { @@ -17,7 +16,6 @@ type SettingItemProps = { selectedStagePerformer: string | null; selectedDealPerformer: string | null; selectedStage: string | null; - utmFile: File | null; questionEntity: TQuestionEntity; tags: TTags; }; @@ -32,7 +30,6 @@ export const SettingItem: FC = ({ selectedStagePerformer, selectedDealPerformer, selectedStage, - utmFile, questionEntity, tags, }) => { @@ -68,17 +65,6 @@ export const SettingItem: FC = ({ ); } if (step === 4) { - return ( - - {utmFile ? ( - - ) : ( - Файл не загружен - )} - - ); - } - if (step === 5) { const isFilled = Object.values(questionEntity).some( (array) => array.length > 0, ); @@ -110,7 +96,7 @@ export const SettingItem: FC = ({ ); } - if (step === 6) { + if (step === 5) { const isFilled = Object.values(tags).some((array) => array.length > 0); const status = isFilled ? "Заполнено" : "Не заполнено"; @@ -148,7 +134,6 @@ export const SettingItem: FC = ({ selectedStagePerformer, selectedDealPerformer, selectedStage, - utmFile, questionEntity, tags, ]); diff --git a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingsBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingsBlock.tsx index 4d7b67ee..434ef61c 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingsBlock.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingsBlock.tsx @@ -13,7 +13,6 @@ type SettingsBlockProps = { selectedStagePerformer: string | null; selectedStage: string | null; selectedDealPerformer: string | null; - utmFile: File | null; questionEntity: TQuestionEntity; tags: TTags; }; @@ -27,7 +26,6 @@ export const SettingsBlock: FC = ({ selectedStagePerformer, selectedDealPerformer, selectedStage, - utmFile, questionEntity, tags, }) => { @@ -68,7 +66,6 @@ export const SettingsBlock: FC = ({ selectedStagePerformer={selectedStagePerformer} selectedDealPerformer={selectedDealPerformer} selectedStage={selectedStage} - utmFile={utmFile} questionEntity={questionEntity} tags={tags} /> diff --git a/src/pages/IntegrationsPage/PartnersBoard/AnalyticsModal/AnalyticsModal.tsx b/src/pages/IntegrationsPage/PartnersBoard/AnalyticsModal/AnalyticsModal.tsx index 677c117b..4ad0f815 100644 --- a/src/pages/IntegrationsPage/PartnersBoard/AnalyticsModal/AnalyticsModal.tsx +++ b/src/pages/IntegrationsPage/PartnersBoard/AnalyticsModal/AnalyticsModal.tsx @@ -25,11 +25,11 @@ interface Props { companyName: keyof typeof QuizMetricType; } -export default function AnalyticsModal({ +export const AnalyticsModal = ({ isModalOpen, handleCloseModal, companyName, -}: Props) { +}: Props) => { const theme = useTheme(); const quiz = useCurrentQuiz(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); @@ -260,4 +260,4 @@ export default function AnalyticsModal({ ); -} +}; diff --git a/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx b/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx index c44b90c0..5510eb08 100644 --- a/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx +++ b/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx @@ -1,12 +1,23 @@ -import { Box, Typography, useTheme } from "@mui/material"; -import React, { FC } from "react"; +import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; +import React, { FC, lazy, Suspense } from "react"; import { ServiceButton } from "./ServiceButton/ServiceButton"; import { YandexMetricaLogo } from "../mocks/YandexMetricaLogo"; -import AnalyticsModal from "./AnalyticsModal/AnalyticsModal"; +// import AnalyticsModal from "./AnalyticsModal/AnalyticsModal"; import { VKPixelLogo } from "../mocks/VKPixelLogo"; import { QuizMetricType } from "@model/quizSettings"; import { AmoCRMLogo } from "../mocks/AmoCRMLogo"; -import { AmoCRMModal } from "../IntegrationsModal/AmoCRMModal"; + +const AnalyticsModal = lazy(() => + import("./AnalyticsModal/AnalyticsModal").then((module) => ({ + default: module.AnalyticsModal, + })), +); + +const AmoCRMModal = lazy(() => + import("../IntegrationsModal/AmoCRMModal").then((module) => ({ + default: module.AmoCRMModal, + })), +); type PartnersBoardProps = { setIsModalOpen: (value: boolean) => void; @@ -30,6 +41,7 @@ export const PartnersBoard: FC = ({ handleCloseAmoSRMModal, }) => { const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); return ( = ({ {companyName && ( - + + + )} {companyName && ( - + + + )} ); diff --git a/src/ui_kit/LabeledDatePicker.tsx b/src/ui_kit/LabeledDatePicker.tsx index bd60b544..261e4450 100644 --- a/src/ui_kit/LabeledDatePicker.tsx +++ b/src/ui_kit/LabeledDatePicker.tsx @@ -11,7 +11,6 @@ import { DatePicker } from "@mui/x-date-pickers"; import moment from "moment"; import type { Moment } from "moment"; - interface Props { label?: string; sx?: SxProps;