From 5434d0cafca7af73c3af432844f51cc40a8aa82e Mon Sep 17 00:00:00 2001 From: aleksandr-raw <104529174+aleksandr-raw@users.noreply.github.com> Date: Thu, 4 Apr 2024 17:48:45 +0400 Subject: [PATCH 01/21] added new IntegrationsPage, setuped routing, added modal --- src/App.tsx | 11 +++ .../IntegrationsModal/IntegrationsModal.tsx | 56 ++++++++++++ .../IntegrationsPage/IntegrationsPage.tsx | 80 ++++++++++++++++++ .../PartnersBoard/PartnerItem/PartnerItem.tsx | 47 ++++++++++ .../PartnersBoard/PartnersBoard.tsx | 70 +++++++++++++++ .../IntegrationsPage/mocks/amoCrmLogo.png | Bin 0 -> 3374 bytes src/ui_kit/Sidebar/Sidebar.tsx | 29 +++++++ 7 files changed, 293 insertions(+) create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsPage.tsx create mode 100644 src/pages/IntegrationsPage/PartnersBoard/PartnerItem/PartnerItem.tsx create mode 100644 src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx create mode 100644 src/pages/IntegrationsPage/mocks/amoCrmLogo.png diff --git a/src/App.tsx b/src/App.tsx index 5045ad9e..f6890e2e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -46,11 +46,15 @@ import OutdatedLink from "./pages/auth/OutdatedLink"; import { useAfterpay } from "@utils/hooks/useAfterpay"; const MyQuizzesFull = lazy(() => import("./pages/createQuize/MyQuizzesFull")); + const ViewPage = lazy(() => import("./pages/ViewPublicationPage")); const Analytics = lazy(() => import("./pages/Analytics/Analytics")); const EditPage = lazy(() => import("./pages/startPage/EditPage")); const { Tariffs } = lazily(() => import("./pages/Tariffs/Tariffs")); const { DesignPage } = lazily(() => import("./pages/DesignPage/DesignPage")); +const { IntegrationsPage } = lazily( + () => import("./pages/IntegrationsPage/IntegrationsPage"), +); const { QuizAnswersPage } = lazily( () => import("./pages/QuizAnswersPage/QuizAnswersPage"), ); @@ -75,6 +79,13 @@ const routeslink = [ sidebar: true, footer: true, }, + { + path: "/integrations", + page: IntegrationsPage, + header: true, + sidebar: true, + footer: true, + }, ] as const; const LazyLoading = ({ children, fallback }: SuspenseProps) => ( diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx new file mode 100644 index 00000000..6a4f656f --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx @@ -0,0 +1,56 @@ +import { Dialog, IconButton, useTheme } from "@mui/material"; +import { FC } from "react"; +import Box from "@mui/material/Box"; +import CloseIcon from "@mui/icons-material/Close"; + +type IntegrationsModalProps = { + isModalOpen: boolean; + setIsModalOpen: (value: boolean) => void; +}; + +export const IntegrationsModal: FC = ({ + isModalOpen, + setIsModalOpen, +}) => { + const theme = useTheme(); + + function handleClose() { + setIsModalOpen(false); + } + + return ( + + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsPage.tsx b/src/pages/IntegrationsPage/IntegrationsPage.tsx new file mode 100644 index 00000000..a4c2ac4a --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsPage.tsx @@ -0,0 +1,80 @@ +import { Skeleton, Typography, useMediaQuery, useTheme } from "@mui/material"; +import React, { useEffect, useState } from "react"; +import Box from "@mui/material/Box"; +import { useCurrentQuiz } from "@root/quizes/hooks"; +import { useQuizStore } from "@root/quizes/store"; +import { useNavigate } from "react-router-dom"; +import { PartnersBoard } from "./PartnersBoard/PartnersBoard"; +import amoCrmLogo from "./mocks/amoCrmLogo.png"; +import { IntegrationsModal } from "./IntegrationsModal/IntegrationsModal"; + +interface IntegrationsPageProps { + heightSidebar: number; + mobileSidebar: boolean; +} + +export const IntegrationsPage = ({ + heightSidebar, + mobileSidebar, +}: IntegrationsPageProps) => { + const quiz = useCurrentQuiz(); + const { editQuizId } = useQuizStore(); + const theme = useTheme(); + const navigate = useNavigate(); + const isMobile = useMediaQuery(theme.breakpoints.down(660)); + const [step, setStep] = useState(0); + const [isModalOpen, setIsModalOpen] = useState(false); + + useEffect(() => { + if (editQuizId === null) navigate("/list"); + }, [navigate, editQuizId]); + + const heightBar = heightSidebar + 51 + 88 + 36 + 25; + + const partnersMock = [ + { category: "CRM", name: "amoCRM", logo: amoCrmLogo }, + { category: "CRM", name: "bitrix" }, + { category: "CRM", name: "RetailCRM." }, + { category: "CRM", name: "SugarCRM." }, + { category: "SocialMedia", name: "Telegram" }, + { category: "SocialMedia", name: "VKontakte" }, + { category: "SocialMedia", name: "X.com" }, + { category: "Сервисы рассылок", name: "Mailchimp" }, + { category: "Сервисы рассылок", name: "GetResponse" }, + { category: "Сервисы рассылок", name: "SendPulse" }, + ]; + if (quiz === undefined) + return ( + + ); + return ( + <> + + + Интеграции + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/PartnersBoard/PartnerItem/PartnerItem.tsx b/src/pages/IntegrationsPage/PartnersBoard/PartnerItem/PartnerItem.tsx new file mode 100644 index 00000000..495d9924 --- /dev/null +++ b/src/pages/IntegrationsPage/PartnersBoard/PartnerItem/PartnerItem.tsx @@ -0,0 +1,47 @@ +import { Box, Typography, useTheme } from "@mui/material"; +import { FC } from "react"; +import { Partner } from "../PartnersBoard"; + +type PartnerItemProps = { + partner: Partner; + setIsModalOpen: (value: boolean) => void; +}; + +export const PartnerItem: FC = ({ + partner, + setIsModalOpen, +}) => { + const theme = useTheme(); + + const handleClick = () => { + setIsModalOpen(true); + }; + + return ( + <> + {partner && ( + + {partner.logo ? ( + {partner.name} + ) : ( + {partner.name} + )} + + )} + + ); +}; diff --git a/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx b/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx new file mode 100644 index 00000000..b0df1552 --- /dev/null +++ b/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx @@ -0,0 +1,70 @@ +import { Box, Typography, useTheme } from "@mui/material"; +import { FC } from "react"; +import { PartnerItem } from "./PartnerItem/PartnerItem"; + +export type Partner = { + name: string; + logo?: string; + category: string; +}; + +type PartnersBoardProps = { + partners: Partner[]; + setIsModalOpen: (value: boolean) => void; +}; + +export const PartnersBoard: FC = ({ + partners, + setIsModalOpen, +}) => { + const theme = useTheme(); + + const partnersByCategory = partners.reduce( + (acc, partner) => { + (acc[partner.category] = acc[partner.category] || []).push(partner); + return acc; + }, + {} as Record, + ); + + return ( + + {Object.entries(partnersByCategory).map(([category, partners]) => ( + + + {category} + + + {partners.map((partner) => ( + + ))} + + + ))} + + ); +}; diff --git a/src/pages/IntegrationsPage/mocks/amoCrmLogo.png b/src/pages/IntegrationsPage/mocks/amoCrmLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..07d03d78474832ac5d0e8cf8e3bd42bed9c98936 GIT binary patch literal 3374 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 literal 0 HcmV?d00001 diff --git a/src/ui_kit/Sidebar/Sidebar.tsx b/src/ui_kit/Sidebar/Sidebar.tsx index 6f179b66..eee51b68 100755 --- a/src/ui_kit/Sidebar/Sidebar.tsx +++ b/src/ui_kit/Sidebar/Sidebar.tsx @@ -178,6 +178,35 @@ export default function Sidebar({ changePage, disableCollapse }: SidebarProps) { /> } /> + { + navigate("/integrations"); + setCurrentStep(16); + }} + text={"Интеграции"} + isCollapsed={isMenuCollapsed} + isActive={pathname.startsWith("/integrations")} + disabled={ + pathname.startsWith("/integrations") + ? false + : quiz === undefined + ? true + : quiz?.config.type === null + } + icon={ + + } + /> {/* {quizSettingsMenuItems.map((menuItem, index) => { const Icon = menuItem[0]; From 137fa317da4125190b9400109479d3f2351f5159 Mon Sep 17 00:00:00 2001 From: aleksandr-raw <104529174+aleksandr-raw@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:48:10 +0400 Subject: [PATCH 02/21] WIP 1step integrations, integrations modal --- .../IntegrationStep1/IntegrationStep1.tsx | 164 ++++++++++++++++++ .../IntegrationStep2/IntegrationStep2.tsx | 38 ++++ .../IntegrationStep3/IntegrationStep3.tsx | 38 ++++ .../IntegrationStep4/IntegrationStep4.tsx | 38 ++++ .../IntegrationStep5/IntegrationStep5.tsx | 38 ++++ .../IntegrationStep6/IntegrationStep6.tsx | 31 ++++ .../IntegrationsModal/IntegrationsModal.tsx | 136 +++++++++++++-- .../StepButtonsBlock/StepButtonsBlock.tsx | 48 +++++ .../IntegrationsPage/IntegrationsPage.tsx | 14 +- .../PartnersBoard/PartnerItem/PartnerItem.tsx | 3 + .../PartnersBoard/PartnersBoard.tsx | 3 + 11 files changed, 536 insertions(+), 15 deletions(-) create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep2/IntegrationStep2.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep3/IntegrationStep3.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep4/IntegrationStep4.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/StepButtonsBlock/StepButtonsBlock.tsx diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx new file mode 100644 index 00000000..5303d94e --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx @@ -0,0 +1,164 @@ +import { Box, Button, Typography, useTheme } from "@mui/material"; +import { FC } from "react"; +import { object, string } from "yup"; +import InputTextfield from "@ui_kit/InputTextfield"; +import PasswordInput from "@ui_kit/passwordInput"; +import { useFormik } from "formik"; +import ArrowLeft from "@icons/questionsPage/arrowLeft"; + +type IntegrationStep1Props = { + handleNextStep: () => void; +}; + +interface Values { + login: string; + password: string; +} + +const initialValues: Values = { + login: "", + password: "", +}; + +const validationSchema = object({ + login: string().required("Поле обязательно"), + password: string().required("Поле обязательно").min(8, "Минимум 8 символов"), +}); + +export const IntegrationStep1: FC = ({ + handleNextStep, +}) => { + const theme = useTheme(); + const formik = useFormik({ + initialValues, + validationSchema, + onSubmit: async (values, formikHelpers) => { + const loginTrimmed = values.login.trim(); + const passwordTrimmed = values.password.trim(); + try { + // Simulate a network request + await new Promise((resolve) => setTimeout(resolve, 2000)); + console.log("Simulated network request completed"); + handleNextStep(); + } catch (error) { + console.error("Errr"); + formikHelpers.setSubmitting(false); + formikHelpers.setErrors({ submit: error.message }); + } + }, + }); + + return ( + + + + + + + + Инструкция + + + Повседневная практика показывает, что постоянный количественный рост и + сфера нашей активности способствует подготовки и реализации систем + массового участия + + + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep2/IntegrationStep2.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep2/IntegrationStep2.tsx new file mode 100644 index 00000000..e5d608f4 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep2/IntegrationStep2.tsx @@ -0,0 +1,38 @@ +import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; +import { FC } from "react"; +import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; + +type IntegrationStep2Props = { + handlePrevStep: () => void; + handleNextStep: () => void; +}; + +export const IntegrationStep2: FC = ({ + handlePrevStep, + handleNextStep, +}) => { + const theme = useTheme(); + const upMd = useMediaQuery(theme.breakpoints.up("md")); + + return ( + + + step 2 + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep3/IntegrationStep3.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep3/IntegrationStep3.tsx new file mode 100644 index 00000000..147e8af1 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep3/IntegrationStep3.tsx @@ -0,0 +1,38 @@ +import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; +import { FC } from "react"; +import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; + +type IntegrationStep3Props = { + handlePrevStep: () => void; + handleNextStep: () => void; +}; + +export const IntegrationStep3: FC = ({ + handlePrevStep, + handleNextStep, +}) => { + const theme = useTheme(); + const upMd = useMediaQuery(theme.breakpoints.up("md")); + + return ( + + + step 3 + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep4/IntegrationStep4.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep4/IntegrationStep4.tsx new file mode 100644 index 00000000..be02f918 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep4/IntegrationStep4.tsx @@ -0,0 +1,38 @@ +import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; +import { FC } from "react"; +import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; + +type IntegrationStep4Props = { + handlePrevStep: () => void; + handleNextStep: () => void; +}; + +export const IntegrationStep4: FC = ({ + handlePrevStep, + handleNextStep, +}) => { + const theme = useTheme(); + const upMd = useMediaQuery(theme.breakpoints.up("md")); + + return ( + + + step 4 + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx new file mode 100644 index 00000000..133aedf4 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx @@ -0,0 +1,38 @@ +import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; +import { FC } from "react"; +import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; + +type IntegrationStep5Props = { + handlePrevStep: () => void; + handleNextStep: () => void; +}; + +export const IntegrationStep5: FC = ({ + handlePrevStep, + handleNextStep, +}) => { + const theme = useTheme(); + const upMd = useMediaQuery(theme.breakpoints.up("md")); + + return ( + + + step 5 + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx new file mode 100644 index 00000000..5560cc9d --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx @@ -0,0 +1,31 @@ +import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; +import { FC } from "react"; + +type IntegrationStep6Props = { + handlePrevStep: () => void; +}; + +export const IntegrationStep6: FC = ({ + handlePrevStep, +}) => { + const theme = useTheme(); + const upMd = useMediaQuery(theme.breakpoints.up("md")); + + return ( + + + step 6 + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx index 6a4f656f..05cf48ad 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx @@ -1,38 +1,121 @@ -import { Dialog, IconButton, useTheme } from "@mui/material"; -import { FC } from "react"; +import { + Dialog, + IconButton, + Typography, + useMediaQuery, + useTheme, +} from "@mui/material"; +import { FC, useMemo, useState } from "react"; import Box from "@mui/material/Box"; import CloseIcon from "@mui/icons-material/Close"; +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"; type IntegrationsModalProps = { isModalOpen: boolean; - setIsModalOpen: (value: boolean) => void; + handleCloseModal: () => void; + companyName: string | null; }; export const IntegrationsModal: FC = ({ isModalOpen, - setIsModalOpen, + handleCloseModal, + companyName, }) => { const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + const isTablet = useMediaQuery(theme.breakpoints.down(1000)); + const [step, setStep] = useState(0); - function handleClose() { - setIsModalOpen(false); - } + const handleNextStep = () => { + setStep((prevState) => prevState + 1); + }; + const handlePrevStep = () => { + setStep((prevState) => prevState - 1); + }; + + const steps = useMemo( + () => [ + { + title: "Авторизация в аккаунте", + component: , + }, + { + title: "Выбор воронки", + component: ( + + ), + }, + { + title: "Выбор этапа воронки", + component: ( + + ), + }, + { + title: "Сделка", + component: ( + + ), + }, + { + title: "Название шага", + component: ( + + ), + }, + { + title: "Добавление тегов", + component: , + }, + ], + [], + ); return ( + + + Интеграция с {companyName ? companyName : "партнером"} + + = ({ + > + + {steps[step].title} + + + Шаг {step + 1} + + {steps[step].component} + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/StepButtonsBlock/StepButtonsBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/StepButtonsBlock/StepButtonsBlock.tsx new file mode 100644 index 00000000..0891d0d0 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/StepButtonsBlock/StepButtonsBlock.tsx @@ -0,0 +1,48 @@ +import { Box, Button, useTheme } from "@mui/material"; +import ArrowLeft from "@icons/questionsPage/arrowLeft"; +import { FC } from "react"; + +type StepButtonsBlockProps = { + handlePrevStep: () => void; + handleNextStep: () => void; +}; + +export const StepButtonsBlock: FC = ({ + handlePrevStep, + handleNextStep, +}) => { + const theme = useTheme(); + return ( + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsPage.tsx b/src/pages/IntegrationsPage/IntegrationsPage.tsx index a4c2ac4a..2764320b 100644 --- a/src/pages/IntegrationsPage/IntegrationsPage.tsx +++ b/src/pages/IntegrationsPage/IntegrationsPage.tsx @@ -22,8 +22,8 @@ export const IntegrationsPage = ({ const theme = useTheme(); const navigate = useNavigate(); const isMobile = useMediaQuery(theme.breakpoints.down(660)); - const [step, setStep] = useState(0); const [isModalOpen, setIsModalOpen] = useState(false); + const [companyName, setCompanyName] = useState(null); useEffect(() => { if (editQuizId === null) navigate("/list"); @@ -47,6 +47,14 @@ export const IntegrationsPage = ({ return ( ); + + const handleCloseModal = () => { + setIsModalOpen(false); + setTimeout(() => { + setCompanyName(null); + }, 300); + }; + return ( <> diff --git a/src/pages/IntegrationsPage/PartnersBoard/PartnerItem/PartnerItem.tsx b/src/pages/IntegrationsPage/PartnersBoard/PartnerItem/PartnerItem.tsx index 495d9924..b780ed4e 100644 --- a/src/pages/IntegrationsPage/PartnersBoard/PartnerItem/PartnerItem.tsx +++ b/src/pages/IntegrationsPage/PartnersBoard/PartnerItem/PartnerItem.tsx @@ -5,15 +5,18 @@ import { Partner } from "../PartnersBoard"; type PartnerItemProps = { partner: Partner; setIsModalOpen: (value: boolean) => void; + setCompanyName: (value: string) => void; }; export const PartnerItem: FC = ({ partner, setIsModalOpen, + setCompanyName, }) => { const theme = useTheme(); const handleClick = () => { + setCompanyName(partner.name); setIsModalOpen(true); }; diff --git a/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx b/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx index b0df1552..d37315bc 100644 --- a/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx +++ b/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx @@ -11,11 +11,13 @@ export type Partner = { type PartnersBoardProps = { partners: Partner[]; setIsModalOpen: (value: boolean) => void; + setCompanyName: (value: string) => void; }; export const PartnersBoard: FC = ({ partners, setIsModalOpen, + setCompanyName, }) => { const theme = useTheme(); @@ -60,6 +62,7 @@ export const PartnersBoard: FC = ({ key={partner.name} partner={partner} setIsModalOpen={setIsModalOpen} + setCompanyName={setCompanyName} /> ))} From 94134bcb46c40f5ec423cbd160e4efb0f6de5f79 Mon Sep 17 00:00:00 2001 From: aleksandr-raw <104529174+aleksandr-raw@users.noreply.github.com> Date: Mon, 8 Apr 2024 18:05:38 +0400 Subject: [PATCH 03/21] added custom select to step 2 --- src/assets/icons/arrow_down.svg | 13 ++ src/components/CustomSelect/CustomSelect.css | 22 +++ src/components/CustomSelect/CustomSelect.tsx | 126 ++++++++++++++++++ .../IntegrationStep1/IntegrationStep1.tsx | 26 +++- .../IntegrationStep2/IntegrationStep2.tsx | 31 +++-- .../IntegrationsModal/IntegrationsModal.tsx | 13 +- 6 files changed, 212 insertions(+), 19 deletions(-) create mode 100644 src/assets/icons/arrow_down.svg create mode 100644 src/components/CustomSelect/CustomSelect.css create mode 100644 src/components/CustomSelect/CustomSelect.tsx diff --git a/src/assets/icons/arrow_down.svg b/src/assets/icons/arrow_down.svg new file mode 100644 index 00000000..1ad046ea --- /dev/null +++ b/src/assets/icons/arrow_down.svg @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/src/components/CustomSelect/CustomSelect.css b/src/components/CustomSelect/CustomSelect.css new file mode 100644 index 00000000..e16e64cc --- /dev/null +++ b/src/components/CustomSelect/CustomSelect.css @@ -0,0 +1,22 @@ +.MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline { + border: 0; +} + +.MuiPaper-root.MuiMenu-paper { + padding-top: 50px; + margin-top: -50px; + border-radius: 28px; +} + +.MuiInputBase-root.MuiOutlinedInput-root { + display: block; +} + +.MuiInputBase-root.MuiOutlinedInput-root > div:first-child, +.MuiInputBase-root.MuiOutlinedInput-root .MuiSelect-icon { + display: none; +} + +.MuiMenu-root.MuiModal-root { + z-index: 0; +} diff --git a/src/components/CustomSelect/CustomSelect.tsx b/src/components/CustomSelect/CustomSelect.tsx new file mode 100644 index 00000000..d235207a --- /dev/null +++ b/src/components/CustomSelect/CustomSelect.tsx @@ -0,0 +1,126 @@ +import { + Avatar, + MenuItem, + Select, + SelectChangeEvent, + Typography, + useMediaQuery, + useTheme, +} from "@mui/material"; +import Box from "@mui/material/Box"; +import { useCallback, useEffect, useRef, useState } from "react"; +import "./CustomSelect.css"; +import arrow_down from "../../assets/icons/arrow_down.svg"; + +type CustomSelectProps = { + items: string[]; + selectedItem: number | null; + setSelectedItem: (num: number) => void; +}; + +export const CustomSelect = ({ + items, + selectedItem, + setSelectedItem, +}: CustomSelectProps) => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + const [opened, setOpened] = useState(false); + const [currentValue, setCurrentValue] = useState(null); + const [placeholder, setPlaceholder] = useState(null); + const ref = useRef(null); + + useEffect(() => { + setCurrentValue(selectedItem !== null ? items[selectedItem] : null); + setPlaceholder( + selectedItem === null ? "Выберите ответственного за сделку" : null, + ); + }, [selectedItem, items]); + + const selectItem = useCallback( + (event: SelectChangeEvent) => { + setCurrentValue(items[Number(event.target.value)]); + setSelectedItem(Number(event.target.value)); + setPlaceholder(null); + }, + [items, setSelectedItem], + ); + + const toggleOpened = useCallback(() => { + setOpened((isOpened) => !isOpened); + }, []); + + return ( + + ref.current?.click()} + > + + + {placeholder || currentValue} + + check + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx index 5303d94e..ba785b6f 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx @@ -1,4 +1,10 @@ -import { Box, Button, Typography, useTheme } from "@mui/material"; +import { + Box, + Button, + Typography, + useMediaQuery, + useTheme, +} from "@mui/material"; import { FC } from "react"; import { object, string } from "yup"; import InputTextfield from "@ui_kit/InputTextfield"; @@ -29,6 +35,9 @@ export const IntegrationStep1: FC = ({ handleNextStep, }) => { const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + const isTablet = useMediaQuery(theme.breakpoints.down(1000)); + const formik = useFormik({ initialValues, validationSchema, @@ -38,12 +47,15 @@ export const IntegrationStep1: FC = ({ try { // Simulate a network request await new Promise((resolve) => setTimeout(resolve, 2000)); - console.log("Simulated network request completed"); handleNextStep(); } catch (error) { - console.error("Errr"); formikHelpers.setSubmitting(false); - formikHelpers.setErrors({ submit: error.message }); + if (error instanceof Error) { + formikHelpers.setErrors({ + login: error.message, + password: error.message, + }); + } } }, }); @@ -56,7 +68,7 @@ export const IntegrationStep1: FC = ({ sx={{ display: "flex", flexDirection: "column", - alignItems: "center", + alignItems: isMobile ? "start" : "center", height: "100%", flexGrow: 1, }} @@ -64,7 +76,7 @@ export const IntegrationStep1: FC = ({ = ({ gap="10px" /> - + void; @@ -12,7 +13,19 @@ export const IntegrationStep2: FC = ({ handleNextStep, }) => { const theme = useTheme(); - const upMd = useMediaQuery(theme.breakpoints.up("md")); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + const isTablet = useMediaQuery(theme.breakpoints.down(1000)); + + const [selectedItem, setSelectedItem] = useState(null); + const itemsMock = [ + "Ангелина Полякова", + "Петр Иванов", + "Алексей Звягинцев", + "Никита Стрельцов", + "Инна Ким", + "Дмитрий Морозов", + "Арсен Тадевосян", + ]; return ( = ({ flexGrow: 1, }} > - - step 2 - + + + = ({ > Интеграция с {companyName ? companyName : "партнером"} @@ -132,7 +137,7 @@ export const IntegrationsModal: FC = ({ sx={{ display: "flex", flexDirection: "column", - width: "920px", + width: isTablet ? "100%" : "920px", height: "600px", padding: "15px 20px 15px", flexGrow: 1, // Add this line @@ -140,7 +145,7 @@ export const IntegrationsModal: FC = ({ > = ({ > Шаг {step + 1} - {steps[step].component} + {steps[step].component} ); From dff10de2d72f939dd43c18b6e69874f7a10e4c19 Mon Sep 17 00:00:00 2001 From: aleksandr-raw <104529174+aleksandr-raw@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:07:42 +0400 Subject: [PATCH 04/21] added 3 step and refactored --- src/assets/icons/Checkbox.tsx | 4 +- .../CustomRadioGroup/CustomRadioGroup.tsx | 72 ++++++++++++++ src/components/CustomSelect/CustomSelect.tsx | 60 ++++++------ .../IntegrationStep1/IntegrationStep1.tsx | 1 + .../IntegrationStep2/IntegrationStep2.tsx | 64 ++++++++---- .../IntegrationStep3/IntegrationStep3.tsx | 58 +++++++++-- .../IntegrationsModal/IntegrationsModal.tsx | 97 ++++++++++++++----- .../IntegrationsPage/IntegrationsPage.tsx | 14 +-- src/pages/IntegrationsPage/mocks/MockData.ts | 42 ++++++++ 9 files changed, 314 insertions(+), 98 deletions(-) create mode 100644 src/components/CustomRadioGroup/CustomRadioGroup.tsx create mode 100644 src/pages/IntegrationsPage/mocks/MockData.ts diff --git a/src/assets/icons/Checkbox.tsx b/src/assets/icons/Checkbox.tsx index 1225b1aa..a569d8b2 100644 --- a/src/assets/icons/Checkbox.tsx +++ b/src/assets/icons/Checkbox.tsx @@ -3,11 +3,13 @@ import { Box, useTheme } from "@mui/material"; interface CheckboxIconProps { checked?: boolean; color?: string; + isRounded?: boolean; } export default function CheckboxIcon({ checked = false, color = "#7E2AEA", + isRounded, }: CheckboxIconProps) { const theme = useTheme(); @@ -16,7 +18,7 @@ export default function CheckboxIcon({ sx={{ height: "24px", width: "24px", - borderRadius: "6px", + borderRadius: isRounded ? "50%" : "6px", display: "flex", justifyContent: "center", alignItems: "center", diff --git a/src/components/CustomRadioGroup/CustomRadioGroup.tsx b/src/components/CustomRadioGroup/CustomRadioGroup.tsx new file mode 100644 index 00000000..181741e3 --- /dev/null +++ b/src/components/CustomRadioGroup/CustomRadioGroup.tsx @@ -0,0 +1,72 @@ +import * as React from "react"; +import { FC } from "react"; +import Radio from "@mui/material/Radio"; +import RadioGroup from "@mui/material/RadioGroup"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import Box from "@mui/material/Box"; +import CheckboxIcon from "@icons/Checkbox"; + +type CustomRadioGroupProps = { + items: string[]; + selectedValue: string | null; + setSelectedValue: (value: string | null) => void; +}; + +export const CustomRadioGroup: FC = ({ + items, + selectedValue, + setSelectedValue, +}) => { + const [currentValue, setCurrentValue] = React.useState( + selectedValue, + ); + const handleChange = (event: React.ChangeEvent) => { + setSelectedValue((event.target as HTMLInputElement).value); + setCurrentValue((event.target as HTMLInputElement).value); + }; + return ( + + + {items.map((item) => ( + + } + icon={} + /> + } + label={item} + labelPlacement={"start"} + /> + ))} + + + ); +}; diff --git a/src/components/CustomSelect/CustomSelect.tsx b/src/components/CustomSelect/CustomSelect.tsx index d235207a..25cf3585 100644 --- a/src/components/CustomSelect/CustomSelect.tsx +++ b/src/components/CustomSelect/CustomSelect.tsx @@ -8,42 +8,34 @@ import { useTheme, } from "@mui/material"; import Box from "@mui/material/Box"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { FC, useCallback, useRef, useState } from "react"; import "./CustomSelect.css"; import arrow_down from "../../assets/icons/arrow_down.svg"; type CustomSelectProps = { items: string[]; - selectedItem: number | null; - setSelectedItem: (num: number) => void; + selectedItem: string | null; + setSelectedItem: (value: string | null) => void; }; -export const CustomSelect = ({ +export const CustomSelect: FC = ({ items, selectedItem, setSelectedItem, -}: CustomSelectProps) => { +}) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); const [opened, setOpened] = useState(false); - const [currentValue, setCurrentValue] = useState(null); - const [placeholder, setPlaceholder] = useState(null); + const [currentValue, setCurrentValue] = useState(selectedItem); const ref = useRef(null); - useEffect(() => { - setCurrentValue(selectedItem !== null ? items[selectedItem] : null); - setPlaceholder( - selectedItem === null ? "Выберите ответственного за сделку" : null, - ); - }, [selectedItem, items]); - - const selectItem = useCallback( + const onSelectItem = useCallback( (event: SelectChangeEvent) => { - setCurrentValue(items[Number(event.target.value)]); - setSelectedItem(Number(event.target.value)); - setPlaceholder(null); + const newValue = event.target.value.toString(); + setCurrentValue(newValue); + setSelectedItem(newValue); }, - [items, setSelectedItem], + [setSelectedItem, setCurrentValue], ); const toggleOpened = useCallback(() => { @@ -54,12 +46,12 @@ export const CustomSelect = ({ - {placeholder || currentValue} + {currentValue || "Выберите ответственного за сделку"} - {items.map((item, index) => ( - - {item} - - ))} + {items.map((item) => { + const uniqueKey = `${item}-${Date.now()}`; + return ( + + {item} + + ); + })} ); diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx index ba785b6f..4cfa17d0 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx @@ -80,6 +80,7 @@ export const IntegrationStep1: FC = ({ display: "flex", flexDirection: "column", alignItems: "center", + gap: "15px", }} > void; handleNextStep: () => void; + selectedFunnelPerformer: string | null; + setSelectedFunnelPerformer: (value: string | null) => void; + selectedFunnel: string | null; + setSelectedFunnel: (value: string | null) => void; + performers: string[]; + funnels: string[]; }; export const IntegrationStep2: FC = ({ handlePrevStep, handleNextStep, + selectedFunnelPerformer, + setSelectedFunnelPerformer, + selectedFunnel, + setSelectedFunnel, + performers, + funnels, }) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isTablet = useMediaQuery(theme.breakpoints.down(1000)); - - const [selectedItem, setSelectedItem] = useState(null); - const itemsMock = [ - "Ангелина Полякова", - "Петр Иванов", - "Алексей Звягинцев", - "Никита Стрельцов", - "Инна Ким", - "Дмитрий Морозов", - "Арсен Тадевосян", - ]; - return ( = ({ flexGrow: 1, }} > - + + + + + + + - ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep3/IntegrationStep3.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep3/IntegrationStep3.tsx index 147e8af1..60e3a38e 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep3/IntegrationStep3.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep3/IntegrationStep3.tsx @@ -1,18 +1,33 @@ -import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; +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"; type IntegrationStep3Props = { handlePrevStep: () => void; handleNextStep: () => void; + selectedStagePerformer: string | null; + setSelectedStagePerformer: (value: string | null) => void; + selectedStage: string | null; + setSelectedStage: (value: string | null) => void; + performers: string[]; + stages: string[]; }; export const IntegrationStep3: FC = ({ handlePrevStep, handleNextStep, + selectedStagePerformer, + setSelectedStagePerformer, + selectedStage, + setSelectedStage, + performers, + stages, }) => { const theme = useTheme(); - const upMd = useMediaQuery(theme.breakpoints.up("md")); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + const isTablet = useMediaQuery(theme.breakpoints.down(1000)); return ( = ({ flexGrow: 1, }} > - + + + - step 3 - - + + + + + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx index 2e63a2de..67287442 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx @@ -1,11 +1,12 @@ import { + Button, Dialog, IconButton, Typography, useMediaQuery, useTheme, } from "@mui/material"; -import { FC, useMemo, useState } from "react"; +import React, { FC, useMemo, useState } from "react"; import Box from "@mui/material/Box"; import CloseIcon from "@mui/icons-material/Close"; import { IntegrationStep1 } from "./IntegrationStep1/IntegrationStep1"; @@ -14,6 +15,8 @@ import { IntegrationStep3 } from "./IntegrationStep3/IntegrationStep3"; import { IntegrationStep4 } from "./IntegrationStep4/IntegrationStep4"; import { IntegrationStep5 } from "./IntegrationStep5/IntegrationStep5"; import { IntegrationStep6 } from "./IntegrationStep6/IntegrationStep6"; +import GearIcon from "@icons/GearIcon"; +import { funnelsMock, performersMock, stagesMock } from "../mocks/MockData"; type IntegrationsModalProps = { isModalOpen: boolean; @@ -29,7 +32,16 @@ export const IntegrationsModal: FC = ({ const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isTablet = useMediaQuery(theme.breakpoints.down(1000)); + const [step, setStep] = useState(0); + const [selectedFunnelPerformer, setSelectedFunnelPerformer] = useState< + string | null + >(null); + const [selectedFunnel, setSelectedFunnel] = useState(null); + const [selectedStagePerformer, setSelectedStagePerformer] = useState< + string | null + >(null); + const [selectedStage, setSelectedStage] = useState(null); const handleNextStep = () => { setStep((prevState) => prevState + 1); @@ -50,6 +62,12 @@ export const IntegrationsModal: FC = ({ ), }, @@ -59,6 +77,12 @@ export const IntegrationsModal: FC = ({ ), }, @@ -140,30 +164,57 @@ export const IntegrationsModal: FC = ({ width: isTablet ? "100%" : "920px", height: "600px", padding: "15px 20px 15px", - flexGrow: 1, // Add this line + flexGrow: 1, }} > - - {steps[step].title} - - - Шаг {step + 1} - + + + + {steps[step].title} + + + Шаг {step + 1} + + + + {steps[step].component} diff --git a/src/pages/IntegrationsPage/IntegrationsPage.tsx b/src/pages/IntegrationsPage/IntegrationsPage.tsx index 2764320b..92ecca6e 100644 --- a/src/pages/IntegrationsPage/IntegrationsPage.tsx +++ b/src/pages/IntegrationsPage/IntegrationsPage.tsx @@ -5,8 +5,8 @@ import { useCurrentQuiz } from "@root/quizes/hooks"; import { useQuizStore } from "@root/quizes/store"; import { useNavigate } from "react-router-dom"; import { PartnersBoard } from "./PartnersBoard/PartnersBoard"; -import amoCrmLogo from "./mocks/amoCrmLogo.png"; import { IntegrationsModal } from "./IntegrationsModal/IntegrationsModal"; +import { partnersMock } from "./mocks/MockData"; interface IntegrationsPageProps { heightSidebar: number; @@ -31,18 +31,6 @@ export const IntegrationsPage = ({ const heightBar = heightSidebar + 51 + 88 + 36 + 25; - const partnersMock = [ - { category: "CRM", name: "amoCRM", logo: amoCrmLogo }, - { category: "CRM", name: "bitrix" }, - { category: "CRM", name: "RetailCRM." }, - { category: "CRM", name: "SugarCRM." }, - { category: "SocialMedia", name: "Telegram" }, - { category: "SocialMedia", name: "VKontakte" }, - { category: "SocialMedia", name: "X.com" }, - { category: "Сервисы рассылок", name: "Mailchimp" }, - { category: "Сервисы рассылок", name: "GetResponse" }, - { category: "Сервисы рассылок", name: "SendPulse" }, - ]; if (quiz === undefined) return ( diff --git a/src/pages/IntegrationsPage/mocks/MockData.ts b/src/pages/IntegrationsPage/mocks/MockData.ts new file mode 100644 index 00000000..2c74b032 --- /dev/null +++ b/src/pages/IntegrationsPage/mocks/MockData.ts @@ -0,0 +1,42 @@ +import amoCrmLogo from "./amoCrmLogo.png"; + +export const partnersMock = [ + { category: "CRM", name: "amoCRM", logo: amoCrmLogo }, + { category: "CRM", name: "bitrix" }, + { category: "CRM", name: "RetailCRM." }, + { category: "CRM", name: "SugarCRM." }, + { category: "SocialMedia", name: "Telegram" }, + { category: "SocialMedia", name: "VKontakte" }, + { category: "SocialMedia", name: "X.com" }, + { category: "Сервисы рассылок", name: "Mailchimp" }, + { category: "Сервисы рассылок", name: "GetResponse" }, + { category: "Сервисы рассылок", name: "SendPulse" }, +]; + +export const performersMock = [ + "Ангелина Полякова", + "Петр Иванов", + "Алексей Звягинцев", + "Никита Стрельцов", + "Инна Ким", + "Дмитрий Морозов", + "Арсен Тадевосян", +]; + +export const funnelsMock = [ + "Воронка 1", + "Воронка 2", + "Воронка 3", + "Воронка 4", + "Воронка 5", + "Воронка 6", +]; + +export const stagesMock = [ + "Этап 1", + "Этап 2", + "Этап 3", + "Этап 4", + "Этап 5", + "Этап 6", +]; From 17a0fd8bc5853133deb62ed8b99ca8d4aebab72e Mon Sep 17 00:00:00 2001 From: aleksandr-raw <104529174+aleksandr-raw@users.noreply.github.com> Date: Tue, 9 Apr 2024 19:38:38 +0400 Subject: [PATCH 05/21] WIP step 5 --- .../CustomFileUploader/CustomFileUploader.tsx | 92 +++++++++++++++++++ .../IntegrationStep4/IntegrationStep4.tsx | 37 ++++++-- .../IntegrationStep5/IntegrationStep5.tsx | 20 ++-- .../IntegrationStep6/IntegrationStep6.tsx | 27 ++++-- .../IntegrationsModal/IntegrationsModal.tsx | 75 ++++++++++----- 5 files changed, 203 insertions(+), 48 deletions(-) create mode 100644 src/components/CustomFileUploader/CustomFileUploader.tsx diff --git a/src/components/CustomFileUploader/CustomFileUploader.tsx b/src/components/CustomFileUploader/CustomFileUploader.tsx new file mode 100644 index 00000000..ffe8a804 --- /dev/null +++ b/src/components/CustomFileUploader/CustomFileUploader.tsx @@ -0,0 +1,92 @@ +import { + Box, + ButtonBase, + Typography, + useMediaQuery, + useTheme, +} from "@mui/material"; +import UploadIcon from "@icons/UploadIcon"; +import { type DragEvent, FC, useRef, useState } from "react"; + +type TextFormat = "txt" | "docx"; + +interface CustomFileUploaderProps { + description?: string; + accept?: TextFormat[]; + handleImageChange: (file: File) => 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(600)); + + 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: "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" : undefined, + }} + onDragEnter={handleDragEnter} + > + + + + Добавить файл + + + {description || "Принимает JPG, PNG, и GIF формат — максимум 5mb"} + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep4/IntegrationStep4.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep4/IntegrationStep4.tsx index be02f918..fef9bccb 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep4/IntegrationStep4.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep4/IntegrationStep4.tsx @@ -1,18 +1,26 @@ -import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; +import { Box, useMediaQuery, useTheme } from "@mui/material"; import { FC } from "react"; import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; +import { CustomSelect } from "../../../../components/CustomSelect/CustomSelect"; type IntegrationStep4Props = { handlePrevStep: () => void; handleNextStep: () => void; + selectedDealPerformer: string | null; + setSelectedDealPerformer: (value: string | null) => void; + performers: string[]; }; export const IntegrationStep4: FC = ({ handlePrevStep, handleNextStep, + selectedDealPerformer, + setSelectedDealPerformer, + performers, }) => { const theme = useTheme(); - const upMd = useMediaQuery(theme.breakpoints.up("md")); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + const isTablet = useMediaQuery(theme.breakpoints.down(1000)); return ( = ({ flexGrow: 1, }} > - + + + - step 4 - - + + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx index 133aedf4..8be5edbd 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx @@ -1,15 +1,21 @@ -import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; +import { Box, useMediaQuery, useTheme } from "@mui/material"; import { FC } from "react"; import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; +import File from "@ui_kit/QuizPreview/QuizPreviewQuestionTypes/File"; +import { CustomFileUploader } from "../../../../components/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")); @@ -24,11 +30,13 @@ export const IntegrationStep5: FC = ({ flexGrow: 1, }} > - - step 5 - + + + void; @@ -9,8 +10,8 @@ export const IntegrationStep6: FC = ({ handlePrevStep, }) => { const theme = useTheme(); - const upMd = useMediaQuery(theme.breakpoints.up("md")); - + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + const isTablet = useMediaQuery(theme.breakpoints.down(1000)); return ( = ({ flexGrow: 1, }} > - - step 6 - + + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx index 67287442..8efae901 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx @@ -17,6 +17,7 @@ import { IntegrationStep5 } from "./IntegrationStep5/IntegrationStep5"; import { IntegrationStep6 } from "./IntegrationStep6/IntegrationStep6"; import GearIcon from "@icons/GearIcon"; import { funnelsMock, performersMock, stagesMock } from "../mocks/MockData"; +import File from "@ui_kit/QuizPreview/QuizPreviewQuestionTypes/File"; type IntegrationsModalProps = { isModalOpen: boolean; @@ -42,6 +43,10 @@ export const IntegrationsModal: FC = ({ string | null >(null); const [selectedStage, setSelectedStage] = useState(null); + const [selectedDealPerformer, setSelectedDealPerformer] = useState< + string | null + >(null); + const [utmFile, setUtmFile] = useState(null); const handleNextStep = () => { setStep((prevState) => prevState + 1); @@ -54,10 +59,12 @@ export const IntegrationsModal: FC = ({ () => [ { title: "Авторизация в аккаунте", + isSettingsAvailable: false, component: , }, { title: "Выбор воронки", + isSettingsAvailable: true, component: ( = ({ }, { title: "Выбор этапа воронки", + isSettingsAvailable: true, component: ( = ({ }, { title: "Сделка", + isSettingsAvailable: true, component: ( ), }, { - title: "Название шага", + title: "Добавление utm-меток", + isSettingsAvailable: false, component: ( ), }, { title: "Добавление тегов", + isSettingsAvailable: true, component: , }, ], - [], + [ + utmFile, + selectedFunnelPerformer, + selectedFunnel, + selectedStagePerformer, + selectedStage, + selectedDealPerformer, + ], ); return ( @@ -191,29 +214,31 @@ export const IntegrationsModal: FC = ({ Шаг {step + 1} - + {steps[step].isSettingsAvailable && ( + + )} {steps[step].component} From 3f7bcc011f89f01884108ea7bd858ac74cfddce9 Mon Sep 17 00:00:00 2001 From: aleksandr-raw <104529174+aleksandr-raw@users.noreply.github.com> Date: Wed, 10 Apr 2024 13:38:30 +0400 Subject: [PATCH 06/21] added 5step, refactored buttons --- .../IntegrationStep1/IntegrationStep1.tsx | 48 ++---------- .../IntegrationStep2/IntegrationStep2.tsx | 4 +- .../IntegrationStep3/IntegrationStep3.tsx | 4 +- .../IntegrationStep4/IntegrationStep4.tsx | 4 +- .../CustomFileUploader/CustomFileUploader.tsx | 6 +- .../IntegrationStep5/IntegrationStep5.tsx | 24 +++--- .../RemoveFileBlock/RemoveFileBlock.tsx | 60 +++++++++++++++ .../IntegrationStep6/IntegrationStep6.tsx | 25 ++---- .../StepButtonsBlock/StepButtonsBlock.tsx | 77 ++++++++++++------- 9 files changed, 149 insertions(+), 103 deletions(-) rename src/{components => pages/IntegrationsPage/IntegrationsModal/IntegrationStep5}/CustomFileUploader/CustomFileUploader.tsx (93%) create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/RemoveFileBlock/RemoveFileBlock.tsx diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx index 4cfa17d0..a1d9b6ea 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx @@ -1,16 +1,10 @@ -import { - Box, - Button, - Typography, - useMediaQuery, - useTheme, -} from "@mui/material"; +import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; import { FC } from "react"; import { object, string } from "yup"; import InputTextfield from "@ui_kit/InputTextfield"; import PasswordInput from "@ui_kit/passwordInput"; import { useFormik } from "formik"; -import ArrowLeft from "@icons/questionsPage/arrowLeft"; +import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; type IntegrationStep1Props = { handleNextStep: () => void; @@ -140,38 +134,12 @@ export const IntegrationStep1: FC = ({ массового участия - - - - + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep2/IntegrationStep2.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep2/IntegrationStep2.tsx index 5d633696..edd16fd2 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep2/IntegrationStep2.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep2/IntegrationStep2.tsx @@ -66,8 +66,8 @@ export const IntegrationStep2: FC = ({ }} > diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep3/IntegrationStep3.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep3/IntegrationStep3.tsx index 60e3a38e..75d77f10 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep3/IntegrationStep3.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep3/IntegrationStep3.tsx @@ -67,8 +67,8 @@ export const IntegrationStep3: FC = ({ }} > diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep4/IntegrationStep4.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep4/IntegrationStep4.tsx index fef9bccb..88009b2e 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep4/IntegrationStep4.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep4/IntegrationStep4.tsx @@ -46,8 +46,8 @@ export const IntegrationStep4: FC = ({ }} > diff --git a/src/components/CustomFileUploader/CustomFileUploader.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/CustomFileUploader/CustomFileUploader.tsx similarity index 93% rename from src/components/CustomFileUploader/CustomFileUploader.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/CustomFileUploader/CustomFileUploader.tsx index ffe8a804..2f8f07c9 100644 --- a/src/components/CustomFileUploader/CustomFileUploader.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/CustomFileUploader/CustomFileUploader.tsx @@ -24,7 +24,7 @@ export const CustomFileUploader: FC = ({ const theme = useTheme(); const dropZone = useRef(null); const [ready, setReady] = useState(false); - const isMobile = useMediaQuery(theme.breakpoints.down(600)); + const isMobile = useMediaQuery(theme.breakpoints.down(700)); const handleDragEnter = (event: DragEvent) => { event.preventDefault(); @@ -65,7 +65,7 @@ export const CustomFileUploader: FC = ({ onDrop={handleDrop} ref={dropZone} sx={{ - width: "580px", + width: isMobile ? "100%" : "580px", padding: isMobile ? "33px" : "33px 10px 33px 55px", display: "flex", alignItems: "center", @@ -73,7 +73,7 @@ export const CustomFileUploader: FC = ({ border: `1px solid ${ready ? "red" : theme.palette.grey2.main}`, borderRadius: "8px", gap: "55px", - flexDirection: isMobile ? "column" : undefined, + flexDirection: isMobile ? "column" : "row", }} onDragEnter={handleDragEnter} > diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx index 8be5edbd..8da67205 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx @@ -1,8 +1,9 @@ import { Box, useMediaQuery, useTheme } from "@mui/material"; -import { FC } from "react"; +import React, { FC } from "react"; import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; import File from "@ui_kit/QuizPreview/QuizPreviewQuestionTypes/File"; -import { CustomFileUploader } from "../../../../components/CustomFileUploader/CustomFileUploader"; +import { RemoveFileBlock } from "./RemoveFileBlock/RemoveFileBlock"; +import { CustomFileUploader } from "./CustomFileUploader/CustomFileUploader"; type IntegrationStep5Props = { handlePrevStep: () => void; @@ -31,15 +32,20 @@ export const IntegrationStep5: FC = ({ }} > - + {utmFile ? ( + + ) : ( + + )} ); diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/RemoveFileBlock/RemoveFileBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/RemoveFileBlock/RemoveFileBlock.tsx new file mode 100644 index 00000000..eb35d9d0 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/RemoveFileBlock/RemoveFileBlock.tsx @@ -0,0 +1,60 @@ +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 RemoveFileBlockProps = { + file: File | null; + setFile: (file: File | null) => void; +}; + +export const RemoveFileBlock: FC = ({ + setFile, + file, +}) => { + const theme = useTheme(); + console.log("theme", theme); + return ( + + + Вы загрузили: + + + + {file?.name} + + setFile(null)} + sx={{ + backgroundColor: "#864BD9", + borderRadius: "50%", + width: "24px", + height: "24px", + color: "white", + }} + > + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx index 98582b53..4dbdd713 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx @@ -1,6 +1,6 @@ -import { Box, Button, useMediaQuery, useTheme } from "@mui/material"; +import { Box, useMediaQuery, useTheme } from "@mui/material"; import { FC } from "react"; -import ArrowLeft from "@icons/questionsPage/arrowLeft"; +import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; type IntegrationStep6Props = { handlePrevStep: () => void; @@ -22,23 +22,10 @@ export const IntegrationStep6: FC = ({ flexGrow: 1, }} > - - - + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/StepButtonsBlock/StepButtonsBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/StepButtonsBlock/StepButtonsBlock.tsx index 0891d0d0..4b032d1d 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/StepButtonsBlock/StepButtonsBlock.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/StepButtonsBlock/StepButtonsBlock.tsx @@ -3,13 +3,27 @@ import ArrowLeft from "@icons/questionsPage/arrowLeft"; import { FC } from "react"; type StepButtonsBlockProps = { - handlePrevStep: () => void; - handleNextStep: () => void; + onSmallBtnClick?: () => void; + onLargeBtnClick?: () => void; + isSmallBtnMissing?: boolean; + isLargeBtnMissing?: boolean; + isSmallBtnDisabled?: boolean; + isLargeBtnDisabled?: boolean; + smallBtnText?: string; + largeBtnText?: string; + largeBtnType?: "button" | "submit" | "reset"; }; export const StepButtonsBlock: FC = ({ - handlePrevStep, - handleNextStep, + onSmallBtnClick, + onLargeBtnClick, + isSmallBtnMissing, + isLargeBtnMissing, + smallBtnText, + largeBtnText, + isSmallBtnDisabled, + isLargeBtnDisabled, + largeBtnType, }) => { const theme = useTheme(); return ( @@ -21,28 +35,39 @@ export const StepButtonsBlock: FC = ({ marginLeft: "auto", }} > - - + {isSmallBtnMissing || ( + + )} + {isLargeBtnMissing || ( + + )} ); }; From d686290df5f9374a24b2fc8c3c28a8bd44c411ec Mon Sep 17 00:00:00 2001 From: aleksandr-raw <104529174+aleksandr-raw@users.noreply.github.com> Date: Wed, 10 Apr 2024 19:49:04 +0400 Subject: [PATCH 07/21] WIP settings in integrations modal --- src/assets/icons/AccountSetting.tsx | 52 +++++++++ .../RemoveFileBlock/RemoveFileBlock.tsx | 1 - .../IntegrationStep6/IntegrationStep6.tsx | 25 ++++- .../IntegrationsModal/IntegrationsModal.tsx | 77 +++++--------- .../IntegrationsModalTitle.tsx | 100 ++++++++++++++++++ .../SettingsBlock/SettingItem/SettingItem.tsx | 16 +++ .../SettingsBlock/SettingsBlock.tsx | 62 +++++++++++ 7 files changed, 275 insertions(+), 58 deletions(-) create mode 100644 src/assets/icons/AccountSetting.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModalTitle/IntegrationsModalTitle.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingsBlock.tsx diff --git a/src/assets/icons/AccountSetting.tsx b/src/assets/icons/AccountSetting.tsx new file mode 100644 index 00000000..7fd40089 --- /dev/null +++ b/src/assets/icons/AccountSetting.tsx @@ -0,0 +1,52 @@ +import { Box } from "@mui/material"; + +interface Props { + color: string; + height: string; + width: string; +} + +export default function AccountSetting({ color, height, width }: Props) { + return ( + + + + + + + + + ); +} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/RemoveFileBlock/RemoveFileBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/RemoveFileBlock/RemoveFileBlock.tsx index eb35d9d0..e4623b67 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/RemoveFileBlock/RemoveFileBlock.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/RemoveFileBlock/RemoveFileBlock.tsx @@ -13,7 +13,6 @@ export const RemoveFileBlock: FC = ({ file, }) => { const theme = useTheme(); - console.log("theme", theme); return ( = ({ flexGrow: 1, }} > - + + + + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx index 8efae901..d9825372 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx @@ -1,5 +1,4 @@ import { - Button, Dialog, IconButton, Typography, @@ -15,9 +14,10 @@ import { IntegrationStep3 } from "./IntegrationStep3/IntegrationStep3"; import { IntegrationStep4 } from "./IntegrationStep4/IntegrationStep4"; import { IntegrationStep5 } from "./IntegrationStep5/IntegrationStep5"; import { IntegrationStep6 } from "./IntegrationStep6/IntegrationStep6"; -import GearIcon from "@icons/GearIcon"; import { funnelsMock, performersMock, stagesMock } from "../mocks/MockData"; import File from "@ui_kit/QuizPreview/QuizPreviewQuestionTypes/File"; +import { IntegrationsModalTitle } from "./IntegrationsModalTitle/IntegrationsModalTitle"; +import { SettingsBlock } from "./SettingsBlock/SettingsBlock"; type IntegrationsModalProps = { isModalOpen: boolean; @@ -35,6 +35,7 @@ export const IntegrationsModal: FC = ({ const isTablet = useMediaQuery(theme.breakpoints.down(1000)); const [step, setStep] = useState(0); + const [isSettingsBlock, setIsSettingsBlock] = useState(false); const [selectedFunnelPerformer, setSelectedFunnelPerformer] = useState< string | null >(null); @@ -190,57 +191,27 @@ export const IntegrationsModal: FC = ({ flexGrow: 1, }} > - - - - {steps[step].title} - - - Шаг {step + 1} - - - {steps[step].isSettingsAvailable && ( - - )} - - {steps[step].component} + + {isSettingsBlock ? ( + + ) : ( + {steps[step].component} + )} ); diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModalTitle/IntegrationsModalTitle.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModalTitle/IntegrationsModalTitle.tsx new file mode 100644 index 00000000..e57a7bbb --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModalTitle/IntegrationsModalTitle.tsx @@ -0,0 +1,100 @@ +import Box from "@mui/material/Box"; +import { Button, Typography, useMediaQuery, useTheme } from "@mui/material"; +import GearIcon from "@icons/GearIcon"; +import React, { FC, useCallback, useMemo } from "react"; +import AccountSetting from "@icons/AccountSetting"; + +type IntegrationsModalTitleProps = { + step: number; + steps: { title: string; isSettingsAvailable: boolean }[]; + isSettingsBlock?: boolean; + setIsSettingsBlock: (value: boolean) => void; + setStep: (value: number) => void; +}; + +export const IntegrationsModalTitle: FC = ({ + step, + steps, + setIsSettingsBlock, + isSettingsBlock, + setStep, +}) => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + + const handleClick = useCallback(() => { + if (isSettingsBlock) { + setIsSettingsBlock(false); + setStep(0); + return; + } + setIsSettingsBlock(true); + }, [isSettingsBlock, setIsSettingsBlock, setStep]); + + const btnText = useMemo(() => { + return isSettingsBlock ? "Сменить аккаунт" : "Мои настройки"; + }, [isSettingsBlock]); + + return ( + + + + {isSettingsBlock ? "Мои настройки" : steps[step].title} + + {isSettingsBlock || ( + + Шаг {step + 1} + + )} + + {steps[step].isSettingsAvailable && ( + + )} + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx new file mode 100644 index 00000000..0e3be045 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx @@ -0,0 +1,16 @@ +import Box from "@mui/material/Box"; +import { FC } from "react"; + +type SettingItemProps = { + step: number; + title: string; + onEditClick: () => void; +}; + +export const SettingItem: FC = ({ + step, + onEditClick, + title, +}) => { + return ; +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingsBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingsBlock.tsx new file mode 100644 index 00000000..ca0e6698 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingsBlock.tsx @@ -0,0 +1,62 @@ +import { FC } from "react"; +import { Box, useMediaQuery, useTheme } from "@mui/material"; +import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; + +type SettingsBlockProps = { + setStep: (value: number) => void; + setIsSettingsBlock: (value: boolean) => void; + selectedFunnelPerformer: string | null; + selectedFunnel: string | null; + selectedStagePerformer: string | null; + selectedStage: string | null; + selectedDealPerformer: string | null; + utmFile: File | null; +}; + +export const SettingsBlock: FC = ({ + setStep, + setIsSettingsBlock, + selectedFunnelPerformer, + selectedFunnel, + selectedStagePerformer, + selectedDealPerformer, + selectedStage, + utmFile, +}) => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + + return ( + + + + setIsSettingsBlock(false)} + isLargeBtnMissing={true} + /> + + + ); +}; From 64e701a036824cfcd3152865a489e7a53b8e7b6e Mon Sep 17 00:00:00 2001 From: aleksandr-raw <104529174+aleksandr-raw@users.noreply.github.com> Date: Fri, 12 Apr 2024 13:05:33 +0400 Subject: [PATCH 08/21] added settings block --- src/assets/icons/EditPencil.tsx | 36 +++++++ .../CustomRadioGroup/CustomRadioGroup.tsx | 17 +++- src/components/CustomSelect/CustomSelect.tsx | 7 +- .../IntegrationStep1/IntegrationStep1.tsx | 9 +- .../CustomFileUploader/CustomFileUploader.tsx | 4 +- .../FileBlock.tsx} | 41 ++++---- .../IntegrationStep5/IntegrationStep5.tsx | 4 +- .../IntegrationsModal/IntegrationsModal.tsx | 25 +++-- .../IntegrationsModalTitle.tsx | 14 +++ .../ResponsiblePerson/ResponsiblePerson.tsx | 38 ++++++++ .../SelectedParameter/SelectedParameter.tsx | 27 ++++++ .../SettingsBlock/SettingItem/SettingItem.tsx | 96 ++++++++++++++++++- .../SettingItemHeader/SettingItemHeader.tsx | 64 +++++++++++++ .../SettingsBlock/SettingsBlock.tsx | 27 +++++- 14 files changed, 357 insertions(+), 52 deletions(-) create mode 100644 src/assets/icons/EditPencil.tsx rename src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/{RemoveFileBlock/RemoveFileBlock.tsx => FileBlock/FileBlock.tsx} (58%) create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/ResponsiblePerson/ResponsiblePerson.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SelectedParameter/SelectedParameter.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItemHeader/SettingItemHeader.tsx diff --git a/src/assets/icons/EditPencil.tsx b/src/assets/icons/EditPencil.tsx new file mode 100644 index 00000000..f9521cac --- /dev/null +++ b/src/assets/icons/EditPencil.tsx @@ -0,0 +1,36 @@ +import { Box } from "@mui/material"; + +interface Props { + color: string; + height: string; + width: string; +} + +export default function EditPencil({ color, height, width }: Props) { + return ( + + + + + + ); +} diff --git a/src/components/CustomRadioGroup/CustomRadioGroup.tsx b/src/components/CustomRadioGroup/CustomRadioGroup.tsx index 181741e3..3710f25d 100644 --- a/src/components/CustomRadioGroup/CustomRadioGroup.tsx +++ b/src/components/CustomRadioGroup/CustomRadioGroup.tsx @@ -5,6 +5,7 @@ import RadioGroup from "@mui/material/RadioGroup"; import FormControlLabel from "@mui/material/FormControlLabel"; import Box from "@mui/material/Box"; import CheckboxIcon from "@icons/Checkbox"; +import { useTheme } from "@mui/material"; type CustomRadioGroupProps = { items: string[]; @@ -17,6 +18,7 @@ export const CustomRadioGroup: FC = ({ selectedValue, setSelectedValue, }) => { + const theme = useTheme(); const [currentValue, setCurrentValue] = React.useState( selectedValue, ); @@ -27,7 +29,7 @@ export const CustomRadioGroup: FC = ({ return ( = ({ sx={{ color: "black", padding: "15px", - borderBottom: "1px solid #F2F3F7", + borderBottom: `1px solid ${theme.palette.background.default}`, display: "flex", justifyContent: "space-between", borderRadius: "12px", margin: 0, - backgroundColor: currentValue === item ? "#F2F3F7" : "white", + backgroundColor: + currentValue === item + ? theme.palette.background.default + : theme.palette.common.white, }} value={item} control={ + } icon={} /> diff --git a/src/components/CustomSelect/CustomSelect.tsx b/src/components/CustomSelect/CustomSelect.tsx index 25cf3585..c98c5d55 100644 --- a/src/components/CustomSelect/CustomSelect.tsx +++ b/src/components/CustomSelect/CustomSelect.tsx @@ -51,8 +51,11 @@ export const CustomSelect: FC = ({ width: "100%", height: "56px", padding: "5px", - color: currentValue === null ? "#9A9AAF" : "#7E2AEA", - border: "2px solid #ffffff", + color: + currentValue === null + ? theme.palette.grey2.main + : theme.palette.brightPurple.main, + border: `2px solid ${theme.palette.common.white}`, borderRadius: "30px", background: "#EFF0F5", display: "flex", diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx index a1d9b6ea..6074d652 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep1/IntegrationStep1.tsx @@ -30,7 +30,6 @@ export const IntegrationStep1: FC = ({ }) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); - const isTablet = useMediaQuery(theme.breakpoints.down(1000)); const formik = useFormik({ initialValues, @@ -87,7 +86,7 @@ export const IntegrationStep1: FC = ({ "data-cy": "login", }} onChange={formik.handleChange} - color="#F2F3F7" + color={theme.palette.background.default} id="login" label="Телефон или E-mail" gap="10px" @@ -103,7 +102,7 @@ export const IntegrationStep1: FC = ({ "data-cy": "password", }} onChange={formik.handleChange} - color="#F2F3F7" + color={theme.palette.background.default} id="password" label="Пароль" gap="10px" @@ -114,7 +113,7 @@ export const IntegrationStep1: FC = ({ sx={{ fontSize: "16px", fontWeight: "400", - color: "#9A9AAF", + color: theme.palette.grey2.main, lineHeight: "1", }} > @@ -125,7 +124,7 @@ export const IntegrationStep1: FC = ({ marginTop: "12px", fontSize: "18px", fontWeight: "400", - color: "#4D4D4D", + color: theme.palette.grey3.main, lineHeight: "1", }} > diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/CustomFileUploader/CustomFileUploader.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/CustomFileUploader/CustomFileUploader.tsx index 2f8f07c9..8d055829 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/CustomFileUploader/CustomFileUploader.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/CustomFileUploader/CustomFileUploader.tsx @@ -82,7 +82,9 @@ export const CustomFileUploader: FC = ({ Добавить файл - + {description || "Принимает JPG, PNG, и GIF формат — максимум 5mb"} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/RemoveFileBlock/RemoveFileBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/FileBlock/FileBlock.tsx similarity index 58% rename from src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/RemoveFileBlock/RemoveFileBlock.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/FileBlock/FileBlock.tsx index e4623b67..89d63fcf 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/RemoveFileBlock/RemoveFileBlock.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/FileBlock/FileBlock.tsx @@ -3,15 +3,12 @@ import Box from "@mui/material/Box"; import { IconButton, Typography, useTheme } from "@mui/material"; import CloseIcon from "@mui/icons-material/Close"; -type RemoveFileBlockProps = { +type FileBlockProps = { file: File | null; - setFile: (file: File | null) => void; + setFile?: (file: File | null) => void; }; -export const RemoveFileBlock: FC = ({ - setFile, - file, -}) => { +export const FileBlock: FC = ({ setFile, file }) => { const theme = useTheme(); return ( @@ -30,7 +27,7 @@ export const RemoveFileBlock: FC = ({ alignItems: "center", backgroundColor: theme.palette.brightPurple.main, borderRadius: "8px", - padding: "5px 5px 5px 14px", + padding: setFile ? "5px 5px 5px 14px" : "5px 14px", gap: "20px", }} > @@ -39,20 +36,22 @@ export const RemoveFileBlock: FC = ({ > {file?.name} - setFile(null)} - sx={{ - backgroundColor: "#864BD9", - borderRadius: "50%", - width: "24px", - height: "24px", - color: "white", - }} - > - - + {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 index 8da67205..dd5a60c1 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep5/IntegrationStep5.tsx @@ -2,7 +2,7 @@ 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 { RemoveFileBlock } from "./RemoveFileBlock/RemoveFileBlock"; +import { FileBlock } from "./FileBlock/FileBlock"; import { CustomFileUploader } from "./CustomFileUploader/CustomFileUploader"; type IntegrationStep5Props = { @@ -33,7 +33,7 @@ export const IntegrationStep5: FC = ({ > {utmFile ? ( - + ) : ( = ({ ], ); + const stepTitles = steps.map((step) => step.title); + return ( = ({ setStep={setStep} /> {isSettingsBlock ? ( - + + + ) : ( {steps[step].component} )} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModalTitle/IntegrationsModalTitle.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModalTitle/IntegrationsModalTitle.tsx index e57a7bbb..62921ff1 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModalTitle/IntegrationsModalTitle.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModalTitle/IntegrationsModalTitle.tsx @@ -90,6 +90,20 @@ export const IntegrationsModalTitle: FC = ({ marginRight: isMobile ? 0 : "8px", marginLeft: 0, }, + "&:hover": { + backgroundColor: theme.palette.brightPurple.main, + color: theme.palette.common.white, + "& path": { + stroke: theme.palette.common.white, + }, + }, + "&:active": { + backgroundColor: "#581CA7", + color: theme.palette.common.white, + "& path": { + stroke: theme.palette.common.white, + }, + }, }} > {isMobile ? "" : btnText} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/ResponsiblePerson/ResponsiblePerson.tsx b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/ResponsiblePerson/ResponsiblePerson.tsx new file mode 100644 index 00000000..8d02911c --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/ResponsiblePerson/ResponsiblePerson.tsx @@ -0,0 +1,38 @@ +import { Typography, useTheme } from "@mui/material"; +import { FC } from "react"; + +type ResponsiblePersonProps = { + performer: string | null; +}; + +export const ResponsiblePerson: FC = ({ + performer, +}) => { + const theme = useTheme(); + + return ( + <> + + Ответственный за сделку: + + + {performer ? performer : "Не выбран"} + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SelectedParameter/SelectedParameter.tsx b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SelectedParameter/SelectedParameter.tsx new file mode 100644 index 00000000..f4d068bb --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SelectedParameter/SelectedParameter.tsx @@ -0,0 +1,27 @@ +import { Typography, useTheme } from "@mui/material"; +import Box from "@mui/material/Box"; +import { FC } from "react"; + +type SelectedParameterProps = { + parameter: string | null; +}; + +export const SelectedParameter: FC = ({ + parameter, +}) => { + const theme = useTheme(); + return ( + + {parameter ? parameter : "Не выбрано"} + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx index 0e3be045..ff3935d8 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx @@ -1,16 +1,104 @@ import Box from "@mui/material/Box"; -import { FC } from "react"; +import { FC, useMemo } from "react"; +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"; type SettingItemProps = { step: number; title: string; - onEditClick: () => void; + setStep: (value: number) => void; + setIsSettingsBlock: (value: boolean) => void; + selectedFunnelPerformer: string | null; + selectedFunnel: string | null; + selectedStagePerformer: string | null; + selectedDealPerformer: string | null; + selectedStage: string | null; + utmFile: File | null; }; export const SettingItem: FC = ({ step, - onEditClick, title, + setStep, + setIsSettingsBlock, + selectedFunnelPerformer, + selectedFunnel, + selectedStagePerformer, + selectedDealPerformer, + selectedStage, + utmFile, }) => { - return ; + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + + if (step === 0) { + return; + } + + const SettingsContent = useMemo(() => { + if (step === 1) { + return ( + <> + + + + ); + } + if (step === 2) { + return ( + <> + + + + ); + } + if (step === 3) { + return ( + <> + + + ); + } + if (step === 4) { + return ( + + {utmFile ? ( + + ) : ( + Файл не загружен + )} + + ); + } + return null; + }, [ + step, + selectedFunnelPerformer, + selectedFunnel, + selectedStagePerformer, + selectedDealPerformer, + selectedStage, + utmFile, + ]); + + return ( + + + {SettingsContent} + + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItemHeader/SettingItemHeader.tsx b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItemHeader/SettingItemHeader.tsx new file mode 100644 index 00000000..61a43ea2 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItemHeader/SettingItemHeader.tsx @@ -0,0 +1,64 @@ +import Box from "@mui/material/Box"; +import { IconButton, Typography, useTheme } from "@mui/material"; +import EditPencil from "@icons/EditPencil"; +import { FC } from "react"; + +type SettingItemHeaderProps = { + title: string; + step: number; + setStep: (value: number) => void; + setIsSettingsBlock: (value: boolean) => void; +}; + +export const SettingItemHeader: FC = ({ + title, + step, + setStep, + setIsSettingsBlock, +}) => { + const theme = useTheme(); + + const handleClick = () => { + setStep(step); + setIsSettingsBlock(false); + }; + + return ( + + + + {step} этап + + + + + + + {title} + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingsBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingsBlock.tsx index ca0e6698..9bd00c9c 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingsBlock.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingsBlock.tsx @@ -1,8 +1,10 @@ import { FC } from "react"; import { Box, useMediaQuery, useTheme } from "@mui/material"; import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; +import { SettingItem } from "./SettingItem/SettingItem"; type SettingsBlockProps = { + stepTitles: string[]; setStep: (value: number) => void; setIsSettingsBlock: (value: boolean) => void; selectedFunnelPerformer: string | null; @@ -14,6 +16,7 @@ type SettingsBlockProps = { }; export const SettingsBlock: FC = ({ + stepTitles, setStep, setIsSettingsBlock, selectedFunnelPerformer, @@ -40,12 +43,30 @@ export const SettingsBlock: FC = ({ sx={{ marginTop: "10px", width: "100%", - height: "100%", + height: "443px", borderRadius: "10px", - padding: "10px", + padding: " 0 20px", boxShadow: "0 0 20px rgba(0, 0, 0, 0.15)", + overflowY: "auto", + flexGrow: 1, }} - > + > + {stepTitles && + stepTitles.map((title, index) => ( + + ))} + Date: Fri, 12 Apr 2024 19:07:37 +0400 Subject: [PATCH 09/21] WIP Step6 and Step 7 --- .../IntegrationStep6/IntegrationStep6.tsx | 23 +++++-- .../IntegrationStep6/Item/Item.tsx | 63 +++++++++++++++++++ .../IntegrationStep7/IntegrationStep6.tsx | 47 ++++++++++++++ .../IntegrationsModal/IntegrationsModal.tsx | 13 +++- src/pages/IntegrationsPage/mocks/MockData.ts | 8 +++ 5 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/Item.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/IntegrationStep6.tsx diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx index e74778f1..c409d2aa 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx @@ -1,20 +1,24 @@ import { Box, useMediaQuery, useTheme } from "@mui/material"; import { FC } from "react"; import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; +import { Item } from "./Item/Item"; +import { someItems } from "../../mocks/MockData"; type IntegrationStep6Props = { handlePrevStep: () => void; + handleNextStep: () => void; }; export const IntegrationStep6: FC = ({ handlePrevStep, + handleNextStep, }) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); - const isTablet = useMediaQuery(theme.breakpoints.down(1000)); return ( = ({ sx={{ marginTop: "20px", width: "100%", - height: "100%", + height: "420px", borderRadius: "10px", padding: "10px", boxShadow: "0 0 20px rgba(0, 0, 0, 0.15)", + display: "flex", + overflowY: "auto", + flexWrap: "wrap", }} - > + > + {/*TODO разобраться что за сущность и какая у нее логика*/} + {someItems && + someItems.map((item) => ( + {}} /> + ))} + + diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/Item.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/Item.tsx new file mode 100644 index 00000000..4f1e58a3 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/Item.tsx @@ -0,0 +1,63 @@ +import { Box, IconButton, Typography, useTheme } from "@mui/material"; +import AddPlus from "@icons/questionsPage/addPlus"; +import { FC } from "react"; + +type ItemProps = { + title: string; + onAddBtnClick: () => void; +}; +//TODO переименовать сущность +export const Item: FC = ({ title, onAddBtnClick }) => { + const theme = useTheme(); + + return ( + + + + {title} + + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/IntegrationStep6.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/IntegrationStep6.tsx new file mode 100644 index 00000000..14d3eb9b --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/IntegrationStep6.tsx @@ -0,0 +1,47 @@ +import { Box, useMediaQuery, useTheme } from "@mui/material"; +import { FC } from "react"; +import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; + +type IntegrationStep7Props = { + handlePrevStep: () => void; +}; + +export const IntegrationStep7: FC = ({ + handlePrevStep, +}) => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + return ( + + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx index 8220e96f..358b1253 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx @@ -18,6 +18,7 @@ import { funnelsMock, performersMock, stagesMock } from "../mocks/MockData"; import File from "@ui_kit/QuizPreview/QuizPreviewQuestionTypes/File"; import { IntegrationsModalTitle } from "./IntegrationsModalTitle/IntegrationsModalTitle"; import { SettingsBlock } from "./SettingsBlock/SettingsBlock"; +import { IntegrationStep7 } from "./IntegrationStep7/IntegrationStep6"; type IntegrationsModalProps = { isModalOpen: boolean; @@ -120,10 +121,20 @@ export const IntegrationsModal: FC = ({ /> ), }, + { + title: "Соотнесение вопросов и сущностей", + isSettingsAvailable: true, + component: ( + + ), + }, { title: "Добавление тегов", isSettingsAvailable: true, - component: , + component: , }, ], [ diff --git a/src/pages/IntegrationsPage/mocks/MockData.ts b/src/pages/IntegrationsPage/mocks/MockData.ts index 2c74b032..7b31aec4 100644 --- a/src/pages/IntegrationsPage/mocks/MockData.ts +++ b/src/pages/IntegrationsPage/mocks/MockData.ts @@ -40,3 +40,11 @@ export const stagesMock = [ "Этап 5", "Этап 6", ]; + +export const someItems = [ + "Контакты", + "Сделки", + "Компании", + "Пользователи", + "Покупатели", +]; From f7bca1ae8272d97ac46d6201589d297125387f18 Mon Sep 17 00:00:00 2001 From: aleksandr-raw <104529174+aleksandr-raw@users.noreply.github.com> Date: Mon, 15 Apr 2024 20:30:40 +0400 Subject: [PATCH 10/21] added step6 --- .../IntegrationStep6/IntegrationStep6.tsx | 106 ++++++++++-------- .../Item/AnswerItem/AnswerItem.tsx | 29 +++++ .../Item/IconBtnAdd/IconBtnAdd.tsx | 46 ++++++++ .../IntegrationStep6/Item/Item.tsx | 58 +++++----- .../ItemDetailsView/ItemDetailsView.tsx | 76 +++++++++++++ .../ItemsSelectionView/ItemsSelectionView.tsx | 60 ++++++++++ ...egrationStep6.tsx => IntegrationStep7.tsx} | 0 .../IntegrationsModal/IntegrationsModal.tsx | 15 ++- .../StepButtonsBlock/StepButtonsBlock.tsx | 7 +- src/pages/IntegrationsPage/mocks/MockData.ts | 8 -- 10 files changed, 317 insertions(+), 88 deletions(-) create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/AnswerItem/AnswerItem.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/IconBtnAdd/IconBtnAdd.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/ItemDetailsView/ItemDetailsView.tsx create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/ItemsSelectionView/ItemsSelectionView.tsx rename src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/{IntegrationStep6.tsx => IntegrationStep7.tsx} (100%) diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx index c409d2aa..17a10a03 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/IntegrationStep6.tsx @@ -1,63 +1,75 @@ -import { Box, useMediaQuery, useTheme } from "@mui/material"; -import { FC } from "react"; -import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; -import { Item } from "./Item/Item"; -import { someItems } from "../../mocks/MockData"; +import { useMediaQuery, useTheme } from "@mui/material"; +import { + Dispatch, + FC, + SetStateAction, + useCallback, + useMemo, + useState, +} from "react"; +import { ItemsSelectionView } from "./ItemsSelectionView/ItemsSelectionView"; +import { ItemDetailsView } from "./ItemDetailsView/ItemDetailsView"; +import { TQuestionEntity } from "../IntegrationsModal"; type IntegrationStep6Props = { handlePrevStep: () => void; handleNextStep: () => void; + questionEntity: TQuestionEntity; + setQuestionEntity: Dispatch>; }; export const IntegrationStep6: FC = ({ handlePrevStep, handleNextStep, + questionEntity, + setQuestionEntity, }) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); - return ( - - - {/*TODO разобраться что за сущность и какая у нее логика*/} - {someItems && - someItems.map((item) => ( - {}} /> - ))} - + const [isSelection, setIsSelection] = useState(false); + const [activeItem, setActiveItem] = useState(null); + const [selectedValue, setSelectedValue] = useState(null); - - { + if (!activeItem || !selectedValue) return; + + setQuestionEntity((prevState) => ({ + ...prevState, + [activeItem]: [selectedValue], + })); + }, [activeItem, setQuestionEntity, selectedValue]); + + const items = useMemo( + () => ["Город", "Имя", "Фамилия", "Отчество", "Контрагент"], + [], + ); + + return ( + <> + {isSelection ? ( + { + setActiveItem(null); + setIsSelection(false); + }} + onLargeBtnClick={() => { + handleAdd(); + setActiveItem(null); + setIsSelection(false); + }} /> - - + ) : ( + + )} + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/AnswerItem/AnswerItem.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/AnswerItem/AnswerItem.tsx new file mode 100644 index 00000000..4120133e --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/AnswerItem/AnswerItem.tsx @@ -0,0 +1,29 @@ +import { Box, Typography, useTheme } from "@mui/material"; +import { FC } from "react"; + +type AnswerItemProps = { + text: string; +}; + +export const AnswerItem: FC = ({ text }) => { + const theme = useTheme(); + return ( + + + {text} + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/IconBtnAdd/IconBtnAdd.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/IconBtnAdd/IconBtnAdd.tsx new file mode 100644 index 00000000..e33e54ee --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/IconBtnAdd/IconBtnAdd.tsx @@ -0,0 +1,46 @@ +import { Box, IconButton, useTheme } from "@mui/material"; +import AddPlus from "@icons/questionsPage/addPlus"; +import { FC } from "react"; + +type IconBtnAddProps = { + onAddBtnClick: () => void; +}; + +export const IconBtnAdd: FC = ({ onAddBtnClick }) => { + const theme = useTheme(); + + return ( + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/Item.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/Item.tsx index 4f1e58a3..6ff514b0 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/Item.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/Item/Item.tsx @@ -1,22 +1,37 @@ -import { Box, IconButton, Typography, useTheme } from "@mui/material"; -import AddPlus from "@icons/questionsPage/addPlus"; +import { Box, Typography, useTheme } from "@mui/material"; import { FC } from "react"; +import { IconBtnAdd } from "./IconBtnAdd/IconBtnAdd"; +import { AnswerItem } from "./AnswerItem/AnswerItem"; +import { TitleKeys, TQuestionEntity } from "../../IntegrationsModal"; + +const titleDictionary = { + contacts: "Контакты", + company: "Компании", + deal: "Сделки", + users: "Пользователи", + buyers: "Покупатели", +}; type ItemProps = { - title: string; + title: TitleKeys; onAddBtnClick: () => void; + questionEntity: TQuestionEntity; }; -//TODO переименовать сущность -export const Item: FC = ({ title, onAddBtnClick }) => { +export const Item: FC = ({ + title, + onAddBtnClick, + questionEntity, +}) => { const theme = useTheme(); - + const translatedTitle = titleDictionary[title]; + const questionEntityTexts = questionEntity[title]; return ( = ({ title, onAddBtnClick }) => { }} > - {title} + {translatedTitle} - - - + {questionEntityTexts && + questionEntityTexts.map((text) => )} + + ); }; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/ItemDetailsView/ItemDetailsView.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/ItemDetailsView/ItemDetailsView.tsx new file mode 100644 index 00000000..0d05fe12 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/ItemDetailsView/ItemDetailsView.tsx @@ -0,0 +1,76 @@ +import { Box } from "@mui/material"; +import { Item } from "../Item/Item"; +import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock"; +import { FC } from "react"; +import { TQuestionEntity } from "../../IntegrationsModal"; + +type TitleKeys = "contacts" | "company" | "deal" | "users" | "buyers"; + +type ItemDetailsViewProps = { + setIsSelection: (value: boolean) => void; + handlePrevStep: () => void; + handleNextStep: () => void; + questionEntity: TQuestionEntity; + setActiveItem: (value: string | null) => void; +}; + +export const ItemDetailsView: FC = ({ + handlePrevStep, + handleNextStep, + questionEntity, + setActiveItem, + setIsSelection, +}) => { + return ( + + + {questionEntity && + Object.keys(questionEntity).map((item) => ( + { + setIsSelection(true); + setActiveItem(item); + }} + questionEntity={questionEntity} + /> + ))} + + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/ItemsSelectionView/ItemsSelectionView.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/ItemsSelectionView/ItemsSelectionView.tsx new file mode 100644 index 00000000..3523352f --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep6/ItemsSelectionView/ItemsSelectionView.tsx @@ -0,0 +1,60 @@ +import { Box } from "@mui/material"; +import { CustomRadioGroup } from "../../../../../components/CustomRadioGroup/CustomRadioGroup"; +import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock"; +import { FC } from "react"; + +type ItemsSelectionViewProps = { + items: string[]; + selectedValue: string | null; + setSelectedValue: (value: string | null) => void; + onLargeBtnClick: () => void; + onSmallBtnClick: () => void; +}; + +export const ItemsSelectionView: FC = ({ + items, + selectedValue, + setSelectedValue, + onLargeBtnClick, + onSmallBtnClick, +}) => { + return ( + + + + + + + + + ); +}; diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/IntegrationStep6.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/IntegrationStep7.tsx similarity index 100% rename from src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/IntegrationStep6.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/IntegrationStep7.tsx diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx index 358b1253..9715341b 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/IntegrationsModal.tsx @@ -18,8 +18,10 @@ import { funnelsMock, performersMock, stagesMock } from "../mocks/MockData"; import File from "@ui_kit/QuizPreview/QuizPreviewQuestionTypes/File"; import { IntegrationsModalTitle } from "./IntegrationsModalTitle/IntegrationsModalTitle"; import { SettingsBlock } from "./SettingsBlock/SettingsBlock"; -import { IntegrationStep7 } from "./IntegrationStep7/IntegrationStep6"; +import { IntegrationStep7 } from "./IntegrationStep7/IntegrationStep7"; +export type TitleKeys = "contacts" | "company" | "deal" | "users" | "buyers"; +export type TQuestionEntity = Record; type IntegrationsModalProps = { isModalOpen: boolean; handleCloseModal: () => void; @@ -49,6 +51,13 @@ export const IntegrationsModal: FC = ({ string | null >(null); const [utmFile, setUtmFile] = useState(null); + const [questionEntity, setQuestionEntity] = useState({ + contacts: [], + company: [], + deal: [], + users: [], + buyers: [], + }); const handleNextStep = () => { setStep((prevState) => prevState + 1); @@ -56,6 +65,7 @@ export const IntegrationsModal: FC = ({ const handlePrevStep = () => { setStep((prevState) => prevState - 1); }; + console.log("questionEntity", questionEntity); const steps = useMemo( () => [ @@ -126,6 +136,8 @@ export const IntegrationsModal: FC = ({ isSettingsAvailable: true, component: ( @@ -138,6 +150,7 @@ export const IntegrationsModal: FC = ({ }, ], [ + questionEntity, utmFile, selectedFunnelPerformer, selectedFunnel, diff --git a/src/pages/IntegrationsPage/IntegrationsModal/StepButtonsBlock/StepButtonsBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/StepButtonsBlock/StepButtonsBlock.tsx index 4b032d1d..d829f09a 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/StepButtonsBlock/StepButtonsBlock.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/StepButtonsBlock/StepButtonsBlock.tsx @@ -38,7 +38,12 @@ export const StepButtonsBlock: FC = ({ {isSmallBtnMissing || ( + + + } + + + + + ) +} diff --git a/src/pages/IntegrationsPage/IntegrationsPage.tsx b/src/pages/IntegrationsPage/IntegrationsPage.tsx index 92ecca6e..4440fa6b 100644 --- a/src/pages/IntegrationsPage/IntegrationsPage.tsx +++ b/src/pages/IntegrationsPage/IntegrationsPage.tsx @@ -38,9 +38,9 @@ export const IntegrationsPage = ({ const handleCloseModal = () => { setIsModalOpen(false); - setTimeout(() => { - setCompanyName(null); - }, 300); + // setTimeout(() => { + // setCompanyName(null); + // }, 300); }; return ( @@ -66,12 +66,14 @@ export const IntegrationsPage = ({ partners={partnersMock} setIsModalOpen={setIsModalOpen} setCompanyName={setCompanyName} - /> - + {/**/} ); diff --git a/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx b/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx index d37315bc..8e7305da 100644 --- a/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx +++ b/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx @@ -1,6 +1,8 @@ import { Box, Typography, useTheme } from "@mui/material"; import { FC } from "react"; import { PartnerItem } from "./PartnerItem/PartnerItem"; +import {YandexButton} from "../IntegrationYandex/YandexButton"; +import YandexModal from "../IntegrationYandex/YandexModal"; export type Partner = { name: string; @@ -12,11 +14,15 @@ type PartnersBoardProps = { partners: Partner[]; setIsModalOpen: (value: boolean) => void; setCompanyName: (value: string) => void; + isModalOpen: boolean; + handleCloseModal: ()=> void }; export const PartnersBoard: FC = ({ partners, setIsModalOpen, + isModalOpen, + handleCloseModal, setCompanyName, }) => { const theme = useTheme(); @@ -38,36 +44,49 @@ export const PartnersBoard: FC = ({ justifyContent: { xs: "center", sm: "center", md: "start" }, }} > - {Object.entries(partnersByCategory).map(([category, partners]) => ( - - (*/} + {/* */} + {/* */} + {/* {category}*/} + {/* */} + {/* */} + {/* {partners.map((partner) => (*/} + {/* */} + {/* ))}*/} + + {/* */} + {/* */} + {/*))}*/} + - {category} - - - {partners.map((partner) => ( - - ))} - - - ))} + > + Аналитика + + + ); }; diff --git a/src/pages/IntegrationsPage/mocks/YandexMetric.png b/src/pages/IntegrationsPage/mocks/YandexMetric.png new file mode 100644 index 0000000000000000000000000000000000000000..96b5ac6619e8e1e6f0eab9c53281147a60119543 GIT binary patch literal 4667 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 literal 0 HcmV?d00001 From 4e9d02efcff27e8df60df6c3b72b279a18e1c95e Mon Sep 17 00:00:00 2001 From: aleksandr-raw <104529174+aleksandr-raw@users.noreply.github.com> Date: Thu, 18 Apr 2024 16:32:46 +0400 Subject: [PATCH 20/21] refactored YandexModal, added yandexMetricNumber to quiz config, added logic to set\update\delate yaNumber --- src/model/quizSettings.ts | 4 +- .../IntegrationYandex/YandexModal.tsx | 274 +++++++++++------- .../IntegrationsPage/IntegrationsPage.tsx | 3 - .../PartnersBoard/PartnersBoard.tsx | 32 +- src/ui_kit/CustomTextField.tsx | 12 +- 5 files changed, 200 insertions(+), 125 deletions(-) diff --git a/src/model/quizSettings.ts b/src/model/quizSettings.ts index f33d87d9..33157780 100644 --- a/src/model/quizSettings.ts +++ b/src/model/quizSettings.ts @@ -2,9 +2,7 @@ import ChartPieIcon from "@icons/ChartPieIcon"; import ContactBookIcon from "@icons/ContactBookIcon"; import FlowArrowIcon from "@icons/FlowArrowIcon"; import LayoutIcon from "@icons/LayoutIcon"; -import MegaphoneIcon from "@icons/MegaphoneIcon"; import QuestionIcon from "@icons/QuestionIcon"; -import QuestionsMapIcon from "@icons/QuestionsMapIcon"; export const quizSetupSteps = [ { @@ -117,6 +115,7 @@ export interface QuizConfig { law?: string; }; meta: string; + yandexMetricNumber: number | undefined; } export type FormContactFieldName = @@ -223,4 +222,5 @@ export const defaultQuizConfig: QuizConfig = { button: "", }, meta: "", + yandexMetricNumber: undefined, }; diff --git a/src/pages/IntegrationsPage/IntegrationYandex/YandexModal.tsx b/src/pages/IntegrationsPage/IntegrationYandex/YandexModal.tsx index 673d548a..c2543032 100644 --- a/src/pages/IntegrationsPage/IntegrationYandex/YandexModal.tsx +++ b/src/pages/IntegrationsPage/IntegrationYandex/YandexModal.tsx @@ -1,112 +1,186 @@ -import {Button, Dialog, IconButton, Typography, useMediaQuery, useTheme} from "@mui/material"; +import { + Button, + Dialog, + IconButton, + Typography, + useMediaQuery, + useTheme, +} from "@mui/material"; import Box from "@mui/material/Box"; import CloseIcon from "@mui/icons-material/Close"; -import React, {useState} from "react"; +import React, { useState } from "react"; import CustomTextField from "@ui_kit/CustomTextField"; -import PencilIcon from "@icons/PencilIcon"; -import PencilCircleIcon from "@icons/PencilCircleIcon"; -import {Pencil} from "@ui_kit/Sidebar/icons/Pencil"; +import EditPencil from "@icons/EditPencil"; +import Trash from "@icons/trash"; +import { updateQuiz } from "@root/quizes/actions"; +import { useCurrentQuiz } from "@root/quizes/hooks"; -interface Props{ - isModalOpen: boolean; - handleCloseModal: () => void; +interface Props { + isModalOpen: boolean; + handleCloseModal: () => void; } -export default function YandexModal({isModalOpen, handleCloseModal}: Props){ - const theme = useTheme(); - const isMobile = useMediaQuery(theme.breakpoints.down(600)); - const isTablet = useMediaQuery(theme.breakpoints.down(1000)); - const [save, setSave] = useState(false) - return ( - (!!yandexNumber); + const [currentValue, setCurrentValue] = useState( + yandexNumber ? yandexNumber.toString() : "", + ); + const handleSave = () => { + updateQuiz(quiz?.id, (quiz) => { + quiz.config.yandexMetricNumber = currentValue + ? Number(currentValue) + : undefined; + }); + handleCloseModal(); + if (!currentValue) { + setIsSave(false); + return; + } + setIsSave(true); + }; + const handleEdit = () => { + setIsSave(false); + }; + + const handleClear = () => { + setCurrentValue(""); + setIsSave(false); + }; + + return ( + + + - - + + + + + + + + + {isSave ? "Ваш номер счетчика" : "Введите номер счетчика"} + + {isSave && ( + + + + + + - Аналитика с Яндекс.Метрикой - - - + + + )} + + + { + const onlyNums = e.target.value.replace(/[^0-9]/g, ""); + setCurrentValue(onlyNums); + }} + /> + + {!isSave && ( + + - - - } - - - - - ) + Сохранить + + + )} + + + ); } diff --git a/src/pages/IntegrationsPage/IntegrationsPage.tsx b/src/pages/IntegrationsPage/IntegrationsPage.tsx index 4440fa6b..c090b11a 100644 --- a/src/pages/IntegrationsPage/IntegrationsPage.tsx +++ b/src/pages/IntegrationsPage/IntegrationsPage.tsx @@ -5,7 +5,6 @@ import { useCurrentQuiz } from "@root/quizes/hooks"; import { useQuizStore } from "@root/quizes/store"; import { useNavigate } from "react-router-dom"; import { PartnersBoard } from "./PartnersBoard/PartnersBoard"; -import { IntegrationsModal } from "./IntegrationsModal/IntegrationsModal"; import { partnersMock } from "./mocks/MockData"; interface IntegrationsPageProps { @@ -24,11 +23,9 @@ export const IntegrationsPage = ({ const isMobile = useMediaQuery(theme.breakpoints.down(660)); const [isModalOpen, setIsModalOpen] = useState(false); const [companyName, setCompanyName] = useState(null); - useEffect(() => { if (editQuizId === null) navigate("/list"); }, [navigate, editQuizId]); - const heightBar = heightSidebar + 51 + 88 + 36 + 25; if (quiz === undefined) diff --git a/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx b/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx index 8e7305da..adf54a60 100644 --- a/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx +++ b/src/pages/IntegrationsPage/PartnersBoard/PartnersBoard.tsx @@ -1,7 +1,6 @@ import { Box, Typography, useTheme } from "@mui/material"; import { FC } from "react"; -import { PartnerItem } from "./PartnerItem/PartnerItem"; -import {YandexButton} from "../IntegrationYandex/YandexButton"; +import { YandexButton } from "../IntegrationYandex/YandexButton"; import YandexModal from "../IntegrationYandex/YandexModal"; export type Partner = { @@ -15,7 +14,7 @@ type PartnersBoardProps = { setIsModalOpen: (value: boolean) => void; setCompanyName: (value: string) => void; isModalOpen: boolean; - handleCloseModal: ()=> void + handleCloseModal: () => void; }; export const PartnersBoard: FC = ({ @@ -75,18 +74,21 @@ export const PartnersBoard: FC = ({ {/* */} {/* */} {/*))}*/} - - Аналитика - - - + + Аналитика + + + ); }; diff --git a/src/ui_kit/CustomTextField.tsx b/src/ui_kit/CustomTextField.tsx index 8b07b20b..5090f98e 100755 --- a/src/ui_kit/CustomTextField.tsx +++ b/src/ui_kit/CustomTextField.tsx @@ -1,15 +1,14 @@ +import type { ChangeEvent, FocusEvent, KeyboardEvent } from "react"; import React, { useEffect, useState } from "react"; +import type { InputProps, SxProps, Theme } from "@mui/material"; import { Box, FormControl, - TextField, - Typography, - useTheme, Input, InputLabel, + Typography, + useTheme, } from "@mui/material"; -import type { ChangeEvent, KeyboardEvent, FocusEvent } from "react"; -import type { InputProps, SxProps, Theme } from "@mui/material"; interface CustomTextFieldProps { placeholder: string; @@ -28,6 +27,7 @@ interface CustomTextFieldProps { type?: string; rows?: number; className?: string; + disabled?: boolean; } export default function CustomTextField({ @@ -47,6 +47,7 @@ export default function CustomTextField({ rows = 0, sxForm, className, + disabled, }: CustomTextFieldProps) { const theme = useTheme(); @@ -115,6 +116,7 @@ export default function CustomTextField({ onKeyDown={onKeyDown} multiline={rows > 0} rows={rows} + disabled={disabled} disableUnderline sx={{ maxLength: maxLength, From b66cdcaee90e6c7788c482a72274876751d54484 Mon Sep 17 00:00:00 2001 From: aleksandr-raw <104529174+aleksandr-raw@users.noreply.github.com> Date: Thu, 18 Apr 2024 18:10:19 +0400 Subject: [PATCH 21/21] integrated yandex metrica script to publications page --- src/api/promocode.ts | 2 +- .../IntegrationYandex/YandexButton.tsx | 61 ++++++++++--------- src/pages/Tariffs/Tariffs.tsx | 14 ++--- src/pages/ViewPublicationPage.tsx | 5 +- src/pages/main.tsx | 5 +- src/utils/hooks/useYandexMetrica.tsx | 29 +++++++++ 6 files changed, 73 insertions(+), 43 deletions(-) create mode 100644 src/utils/hooks/useYandexMetrica.tsx diff --git a/src/api/promocode.ts b/src/api/promocode.ts index 51374e1a..1c93dae0 100644 --- a/src/api/promocode.ts +++ b/src/api/promocode.ts @@ -15,7 +15,7 @@ export async function activatePromocode(promocode: string) { contentType: true, body: { codeword: promocode }, }); - console.log(response) + console.log(response); return response.greetings; } catch (nativeError) { diff --git a/src/pages/IntegrationsPage/IntegrationYandex/YandexButton.tsx b/src/pages/IntegrationsPage/IntegrationYandex/YandexButton.tsx index 43894b6c..64e6e843 100644 --- a/src/pages/IntegrationsPage/IntegrationYandex/YandexButton.tsx +++ b/src/pages/IntegrationsPage/IntegrationYandex/YandexButton.tsx @@ -3,38 +3,39 @@ import { FC } from "react"; import YandexMetric from "../mocks/YandexMetric.png"; type PartnerItemProps = { - setIsModalOpen: (value: boolean) => void; - setCompanyName?: (value: string) => void; + setIsModalOpen: (value: boolean) => void; + setCompanyName?: (value: string) => void; }; -export const YandexButton: FC = ({setIsModalOpen, - setCompanyName,}) => { - const theme = useTheme(); +export const YandexButton: FC = ({ + setIsModalOpen, + setCompanyName, +}) => { + const theme = useTheme(); - const handleClick = () => { - setIsModalOpen(true); - }; + const handleClick = () => { + setIsModalOpen(true); + }; - return ( - <> - setIsModalOpen(true)} - > - {"Yandex.Метрика"} - - - - ); + return ( + <> + setIsModalOpen(true)} + > + {"Yandex.Метрика"} + + + ); }; diff --git a/src/pages/Tariffs/Tariffs.tsx b/src/pages/Tariffs/Tariffs.tsx index a7a95f16..0e4f9719 100644 --- a/src/pages/Tariffs/Tariffs.tsx +++ b/src/pages/Tariffs/Tariffs.tsx @@ -172,18 +172,18 @@ function TariffPage() { return tariff.privileges[0].privilegeId !== "squizHideBadge"; }); - function handleApplyPromocode () { + function handleApplyPromocode() { if (!promocodeField) return; activatePromocode(promocodeField) .then(async (greetings) => { - enqueueSnackbar(greetings) + enqueueSnackbar(greetings); - const discounts = await makeRequest({ - method: "GET", - url: `${process.env.REACT_APP_DOMAIN}/price/discount/user/${userId}`, - }); - setDiscounts(discounts.Discounts); + const discounts = await makeRequest({ + method: "GET", + url: `${process.env.REACT_APP_DOMAIN}/price/discount/user/${userId}`, + }); + setDiscounts(discounts.Discounts); }) .catch(enqueueSnackbar); } diff --git a/src/pages/ViewPublicationPage.tsx b/src/pages/ViewPublicationPage.tsx index c4432546..9e3e6d8e 100644 --- a/src/pages/ViewPublicationPage.tsx +++ b/src/pages/ViewPublicationPage.tsx @@ -8,6 +8,7 @@ import { isAxiosError } from "axios"; import { enqueueSnackbar } from "notistack"; import { useParams } from "react-router-dom"; import useSWR from "swr"; +import { useYandexMetrica } from "@utils/hooks/useYandexMetrica"; export default function ViewPublicationPage() { const quizId = useParams().quizId; @@ -20,6 +21,9 @@ export default function ViewPublicationPage() { if (!quizId) return null; const quiz = quizes?.find((quiz) => quiz.qid === quizId); + const yandexMetricNumber = quiz?.config.yandexMetricNumber; + + useYandexMetrica(yandexMetricNumber); const { data: rawQuestions, @@ -56,7 +60,6 @@ export default function ViewPublicationPage() { if (!rawQuestions) throw new Error("Questions not found"); const questions = rawQuestions.map(rawQuestionToQuestion); - return ( state.currentStep); const { isTestServer } = useDomainDefine(); - useEffect(() => { const getData = async () => { const quizes = await quizApi.getList(); diff --git a/src/utils/hooks/useYandexMetrica.tsx b/src/utils/hooks/useYandexMetrica.tsx new file mode 100644 index 00000000..a2232993 --- /dev/null +++ b/src/utils/hooks/useYandexMetrica.tsx @@ -0,0 +1,29 @@ +import { useEffect } from "react"; + +export const useYandexMetrica = (yandexMetricNumber: number | undefined) => { + useEffect(() => { + if (yandexMetricNumber) { + const script = document.createElement("script"); + script.type = "text/javascript"; + script.innerHTML = ` + (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; + m[i].l=1*new Date(); + for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }} + k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) + (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); + + ym(${yandexMetricNumber}, "init", { + clickmap:true, + trackLinks:true, + accurateTrackBounce:true, + webvisor:true + }); + `; + document.body.appendChild(script); + + const noscript = document.createElement("noscript"); + noscript.innerHTML = `
`; + document.body.appendChild(noscript); + } + }, [yandexMetricNumber]); +};