корректная работа скроллов, работает удаление ячеек

This commit is contained in:
Nastya 2024-08-14 04:19:14 +03:00
parent 0c7a54d4ba
commit 924c488af3
15 changed files with 280 additions and 277 deletions

@ -1,5 +1,5 @@
import { Button, Typography, useMediaQuery, useTheme } from "@mui/material"; import { Button, Typography, useMediaQuery, useTheme } from "@mui/material";
import AmoLogo from "../../assets/icons/Amologo.png"; import AmoLogo from "@/assets/icons/Amologo.png";
import { FC } from "react"; import { FC } from "react";
type AmoButtonProps = { type AmoButtonProps = {

@ -3,6 +3,8 @@ import { FC, useMemo } from "react";
import CheckboxIcon from "@icons/Checkbox"; import CheckboxIcon from "@icons/Checkbox";
import { SelectChangeEvent, Typography, useTheme, Box, FormControlLabel, RadioGroup, Radio, useMediaQuery } from "@mui/material"; import { SelectChangeEvent, Typography, useTheme, Box, FormControlLabel, RadioGroup, Radio, useMediaQuery } from "@mui/material";
import { MinifiedData, TagKeys } from "@/pages/IntegrationsPage/IntegrationsModal/Amo/types"; import { MinifiedData, TagKeys } from "@/pages/IntegrationsPage/IntegrationsModal/Amo/types";
import { determineScrollBottom } from "@/utils/throttle";
import { throttle } from "@frontend/kitui";
type CustomRadioGroupProps = { type CustomRadioGroupProps = {
items: MinifiedData[] | []; items: MinifiedData[] | [];
@ -34,17 +36,6 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
return item.entity === activeScope; return item.entity === activeScope;
}) : items }) : items
const onScroll = React.useCallback((e: React.UIEvent<HTMLDivElement>) => {
const scrollHeight = e.currentTarget.scrollHeight;
const scrollTop = e.currentTarget.scrollTop;
const clientHeight = e.currentTarget.clientHeight;
const scrolledToBottom = scrollTop / (scrollHeight - clientHeight) > 0.9;
if (scrolledToBottom) {
handleScroll();
}
}, []);
const formControlLabels = const formControlLabels =
(filteredItems.length !== 0) ? (filteredItems.length !== 0) ?
filteredItems.map((item) => ( filteredItems.map((item) => (
@ -101,7 +92,8 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
return ( return (
<Box <Box
onScroll={handleScroll}
onScroll={(e) => determineScrollBottom(e, throttle(handleScroll, 700))}
sx={{ sx={{
border: `1px solid ${theme.palette.grey2.main}`, border: `1px solid ${theme.palette.grey2.main}`,
borderRadius: "12px", borderRadius: "12px",
@ -115,7 +107,6 @@ export const CustomRadioGroup: FC<CustomRadioGroupProps> = ({
name="controlled-radio-buttons-group" name="controlled-radio-buttons-group"
value={selectedItemId} value={selectedItemId}
onChange={({ target }: SelectChangeEvent<string>) => setSelectedItem(target.value)} onChange={({ target }: SelectChangeEvent<string>) => setSelectedItem(target.value)}
onScroll={onScroll}
> >
{formControlLabels} {formControlLabels}
</RadioGroup> </RadioGroup>

@ -1,8 +1,10 @@
import * as React from "react"; import * as React from "react";
import { FC, useCallback, useMemo, useRef, useState } from "react"; import { FC, useCallback, useMemo, useRef, useState } from "react";
import { Avatar, MenuItem, Select, SelectChangeEvent, Typography, useMediaQuery, useTheme, Box } from "@mui/material"; import { Avatar, MenuItem, Select, SelectChangeEvent, Typography, useMediaQuery, useTheme, Box } from "@mui/material";
import arrow_down from "../../assets/icons/arrow_down.svg"; import arrow_down from "@/assets/icons/arrow_down.svg";
import { MinifiedData } from "@/pages/IntegrationsPage/IntegrationsModal/Amo/types"; import { MinifiedData } from "@/pages/IntegrationsPage/IntegrationsModal/Amo/types";
import { throttle } from "@frontend/kitui";
import { determineScrollBottom } from "@/utils/throttle";
type CustomSelectProps = { type CustomSelectProps = {
items: MinifiedData[] | []; items: MinifiedData[] | [];
@ -22,17 +24,6 @@ export const CustomSelect: FC<CustomSelectProps> = ({ items, selectedItemId, set
setOpened((isOpened) => !isOpened); setOpened((isOpened) => !isOpened);
}, []); }, []);
const onScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
const scrollHeight = e.currentTarget.scrollHeight;
const scrollTop = e.currentTarget.scrollTop;
const clientHeight = e.currentTarget.clientHeight;
const scrolledToBottom = scrollTop / (scrollHeight - clientHeight) > 0.9;
if (scrolledToBottom) {
handleScroll();
}
}, []);
const currentItem = useMemo(() => items.find((item) => item.id === selectedItemId) || null, [selectedItemId, items]); const currentItem = useMemo(() => items.find((item) => item.id === selectedItemId) || null, [selectedItemId, items]);
const menuItems = useMemo(() => { const menuItems = useMemo(() => {
@ -149,7 +140,7 @@ export const CustomSelect: FC<CustomSelectProps> = ({ items, selectedItemId, set
MenuProps={{ MenuProps={{
disablePortal: true, disablePortal: true,
PaperProps: { PaperProps: {
onScroll: onScroll, onScroll: (e) => determineScrollBottom(e, throttle(handleScroll, 700)),
style: { style: {
zIndex: 2, zIndex: 2,
maxHeight: "300px", maxHeight: "300px",

@ -18,6 +18,7 @@ type Props = {
desc: string; desc: string;
toSettings: () => void; toSettings: () => void;
} }
onScrollUsers: () => void;
}; };
export const DealPerformers: FC<Props> = ({ export const DealPerformers: FC<Props> = ({
@ -26,6 +27,7 @@ export const DealPerformers: FC<Props> = ({
handleNextStep, handleNextStep,
selectedDealUser, selectedDealUser,
setSelectedDealPerformer, setSelectedDealPerformer,
onScrollUsers,
titleProps, titleProps,
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
@ -52,7 +54,7 @@ export const DealPerformers: FC<Props> = ({
items={users} items={users}
selectedItemId={selectedDealUser} selectedItemId={selectedDealUser}
setSelectedItem={setSelectedDealPerformer} setSelectedItem={setSelectedDealPerformer}
handleScroll={() => {}} handleScroll={onScrollUsers}
/> />
</Box> </Box>
<Box <Box

@ -22,6 +22,8 @@ type Props = {
desc: string; desc: string;
toSettings: () => void; toSettings: () => void;
} }
onScroll: () => void;
onScrollUsers: () => void;
}; };
export const PipelineSteps: FC<Props> = ({ export const PipelineSteps: FC<Props> = ({
@ -32,6 +34,9 @@ export const PipelineSteps: FC<Props> = ({
steps, steps,
selectedStep, selectedStep,
setSelectedStep, setSelectedStep,
onScroll,
onScrollUsers,
handlePrevStep, handlePrevStep,
handleNextStep, handleNextStep,
@ -59,7 +64,7 @@ export const PipelineSteps: FC<Props> = ({
height: "100%", height: "100%",
overflow: "auto", overflow: "auto",
zIndex: 3, zIndex: 3,
width: "100%", width: "100%",
}}> }}>
<Box sx={{ width: "100%", zIndex: 3 }}> <Box sx={{ width: "100%", zIndex: 3 }}>
<ModalTitle <ModalTitle
@ -69,7 +74,7 @@ export const PipelineSteps: FC<Props> = ({
items={users} items={users}
selectedItemId={selectedDealUser} selectedItemId={selectedDealUser}
setSelectedItem={setSelectedDealPerformer} setSelectedItem={setSelectedDealPerformer}
handleScroll={() => { }} handleScroll={onScrollUsers}
/> />
</Box> </Box>
<Box <Box
@ -83,7 +88,7 @@ export const PipelineSteps: FC<Props> = ({
items={steps} items={steps}
selectedItemId={selectedStep} selectedItemId={selectedStep}
setSelectedItem={setSelectedStep} setSelectedItem={setSelectedStep}
handleScroll={() => { }} handleScroll={onScroll}
/> />
</Box> </Box>
</Box> </Box>

@ -22,6 +22,8 @@ type Props = {
desc: string; desc: string;
toSettings: () => void; toSettings: () => void;
} }
onScroll: () => void;
onScrollUsers: () => void;
}; };
export const Pipelines: FC<Props> = ({ export const Pipelines: FC<Props> = ({
@ -33,6 +35,8 @@ export const Pipelines: FC<Props> = ({
users, users,
selectedDealUser, selectedDealUser,
setSelectedDealPerformer, setSelectedDealPerformer,
onScroll,
onScrollUsers,
handlePrevStep, handlePrevStep,
handleNextStep, handleNextStep,
@ -67,7 +71,7 @@ export const Pipelines: FC<Props> = ({
items={users} items={users}
selectedItemId={selectedDealUser} selectedItemId={selectedDealUser}
setSelectedItem={setSelectedDealPerformer} setSelectedItem={setSelectedDealPerformer}
handleScroll={() => { }} handleScroll={onScrollUsers}
/> />
</Box> </Box>
<Box <Box
@ -81,7 +85,7 @@ export const Pipelines: FC<Props> = ({
items={pipelines} items={pipelines}
selectedItemId={selectedPipeline} selectedItemId={selectedPipeline}
setSelectedItem={setSelectedPipeline} setSelectedItem={setSelectedPipeline}
handleScroll={() => { }} handleScroll={onScroll}
/> />
</Box> </Box>
</Box> </Box>

@ -25,6 +25,7 @@ type Props = {
title: string; title: string;
toSettings: () => void; toSettings: () => void;
} }
onScroll: () => void;
}; };
export type QuestionPair = { export type QuestionPair = {
question: string, question: string,
@ -48,6 +49,7 @@ export const AmoQuestions: FC<Props> = ({
openDelete, openDelete,
FieldsAllowedFC, FieldsAllowedFC,
setSelectedCurrentFields, setSelectedCurrentFields,
onScroll,
titleProps, titleProps,
}) => { }) => {
const [isSelection, setIsSelection] = useState<boolean>(false); const [isSelection, setIsSelection] = useState<boolean>(false);
@ -167,18 +169,10 @@ export const AmoQuestions: FC<Props> = ({
selectedField={selectedField} selectedField={selectedField}
selectedCurrentFields={selectedCurrentFields} selectedCurrentFields={selectedCurrentFields}
setSelectedField={setSelectedField} setSelectedField={setSelectedField}
onSmallBtnClick={() => {
setActiveScope(null);
setIsSelection(false);
}}
onLargeBtnClick={() => {
handleAdd();
setActiveScope(null);
setIsSelection(false);
}}
activeScope={activeScope} activeScope={activeScope}
setIsCurrentFields={setIsCurrentFields} setIsCurrentFields={setIsCurrentFields}
isCurrentFields={isCurrentFields} isCurrentFields={isCurrentFields}
handleScroll={onScroll}
/> />
</> </>
) : ( ) : (
@ -204,11 +198,28 @@ export const AmoQuestions: FC<Props> = ({
alignSelf: "end", alignSelf: "end",
}} }}
> >
<StepButtonsBlock {isSelection && activeScope !== null ?
onSmallBtnClick={handlePrevStep} <StepButtonsBlock
onLargeBtnClick={handleNextStep} onLargeBtnClick={() => {
largeBtnText={"Сохранить"} handleAdd();
/> setActiveScope(null);
setIsSelection(false);
}}
largeBtnText={"Добавить"}
onSmallBtnClick={() => {
setActiveScope(null);
setIsSelection(false);
}}
smallBtnText={"Отменить"}
/>
:
<StepButtonsBlock
onSmallBtnClick={handlePrevStep}
onLargeBtnClick={handleNextStep}
largeBtnText={"Сохранить"}
/>
}
</Box> </Box>
</> </>
); );

@ -1,8 +1,8 @@
import { CustomRadioGroup } from "@/components/CustomRadioGroup/CustomRadioGroup" import { CustomRadioGroup } from "@/components/CustomRadioGroup/CustomRadioGroup"
import {Box, Typography, useMediaQuery, useTheme} from "@mui/material" import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"
import { MinifiedData } from "../types"; import { MinifiedData } from "../types";
import {CustomSelect} from "@/components/CustomSelect/CustomSelect"; import { CustomSelect } from "@/components/CustomSelect/CustomSelect";
import {CurrentFieldSelect} from "@/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/CurrentFieldSelectMobile"; import { CurrentFieldSelect } from "@/pages/IntegrationsPage/IntegrationsModal/Amo/Questions/CurrentFieldSelectMobile";
interface Props { interface Props {
items: MinifiedData[]; items: MinifiedData[];
@ -11,6 +11,7 @@ interface Props {
currentQuestion: string; currentQuestion: string;
setCurrentField: (value: string) => void; setCurrentField: (value: string) => void;
setCurrentQuestion: (value: string) => void; setCurrentQuestion: (value: string) => void;
handleScroll: () => void;
} }
export const CurrentFields = ({ export const CurrentFields = ({
items, items,
@ -19,6 +20,7 @@ export const CurrentFields = ({
currentQuestion, currentQuestion,
setCurrentField, setCurrentField,
setCurrentQuestion, setCurrentQuestion,
handleScroll,
}: Props) => { }: Props) => {
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isMobile = useMediaQuery(theme.breakpoints.down(600));
@ -53,18 +55,18 @@ export const CurrentFields = ({
{isMobile && {isMobile &&
<CurrentFieldSelect <CurrentFieldSelect
items={fieldsItems} items={fieldsItems}
selectedItemId={currentField selectedItemId={currentField}
} setSelectedItem={setCurrentField} setSelectedItem={setCurrentField}
handleScroll={() => { }}/> handleScroll={handleScroll} />
} }
{!isMobile && {!isMobile &&
<CustomRadioGroup <CustomRadioGroup
items={fieldsItems} items={fieldsItems}
selectedItemId={currentField} selectedItemId={currentField}
setSelectedItem={setCurrentField} setSelectedItem={setCurrentField}
handleScroll={() => { }} handleScroll={handleScroll}
activeScope={undefined} activeScope={undefined}
/> />
} }
</Box> </Box>
@ -85,20 +87,20 @@ export const CurrentFields = ({
}} }}
>Выберите вопрос для этого поля</Typography> >Выберите вопрос для этого поля</Typography>
{isMobile && {isMobile &&
<CurrentFieldSelect <CurrentFieldSelect
items={items} items={items}
selectedItemId={currentQuestion} selectedItemId={currentQuestion}
setSelectedItem={setCurrentQuestion} setSelectedItem={setCurrentQuestion}
handleScroll={() => { }}/> handleScroll={() => { }} />
} }
{!isMobile && {!isMobile &&
<CustomRadioGroup <CustomRadioGroup
items={items} items={items}
selectedItemId={currentQuestion} selectedItemId={currentQuestion}
setSelectedItem={setCurrentQuestion} setSelectedItem={setCurrentQuestion}
handleScroll={() => { }} handleScroll={() => { }}
activeScope={undefined} activeScope={undefined}
/> />
} }
</Box> </Box>

@ -14,9 +14,7 @@ type ItemsSelectionViewProps = {
setSelectedQuestion: (value: string | null) => void; setSelectedQuestion: (value: string | null) => void;
selectedField?: string | null; selectedField?: string | null;
setSelectedField: (value: string | null) => void; setSelectedField: (value: string | null) => void;
handleScroll?: () => void; handleScroll: () => void;
onLargeBtnClick: () => void;
onSmallBtnClick: () => void;
activeScope: TagKeys; activeScope: TagKeys;
FieldsAllowedFC: MinifiedData[]; FieldsAllowedFC: MinifiedData[];
selectedCurrentFields: MinifiedData[]; selectedCurrentFields: MinifiedData[];
@ -31,8 +29,6 @@ export const EntitiesQuestions: FC<ItemsSelectionViewProps> = ({
selectedField, selectedField,
setSelectedField, setSelectedField,
handleScroll, handleScroll,
onLargeBtnClick,
onSmallBtnClick,
activeScope, activeScope,
FieldsAllowedFC, FieldsAllowedFC,
selectedCurrentFields, selectedCurrentFields,
@ -41,13 +37,6 @@ export const EntitiesQuestions: FC<ItemsSelectionViewProps> = ({
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isMobile = useMediaQuery(theme.breakpoints.down(600));
console.log("--------------")
console.log("EntitiesQuestions")
console.log("вопросы")
console.log(items)
console.log("ФК")
console.log(FieldsAllowedFC)
console.log("------------------------------")
return ( return (
<Box <Box
@ -105,6 +94,7 @@ export const EntitiesQuestions: FC<ItemsSelectionViewProps> = ({
currentQuestion={selectedItemId} currentQuestion={selectedItemId}
setCurrentField={setSelectedField} setCurrentField={setSelectedField}
setCurrentQuestion={setSelectedQuestion} setCurrentQuestion={setSelectedQuestion}
handleScroll={handleScroll}
/> />
: :
<NewFields <NewFields
@ -114,21 +104,6 @@ export const EntitiesQuestions: FC<ItemsSelectionViewProps> = ({
/> />
} }
</Box> </Box>
<Box
sx={{
marginTop: "20px",
alignSelf: "end",
}}
>
<StepButtonsBlock
onLargeBtnClick={() => {
onLargeBtnClick()
}}
largeBtnText={"Добавить"}
onSmallBtnClick={onSmallBtnClick}
smallBtnText={"Отменить"}
/>
</Box>
</Box> </Box>
) )
} }

@ -9,8 +9,6 @@ type ItemsSelectionViewProps = {
selectedItemId?: string | null; selectedItemId?: string | null;
setSelectedItem: (value: string | null) => void; setSelectedItem: (value: string | null) => void;
handleScroll?: () => void; handleScroll?: () => void;
onLargeBtnClick: () => void;
onSmallBtnClick: () => void;
activeScope: TagKeys; activeScope: TagKeys;
}; };
@ -19,8 +17,6 @@ export const ItemsSelectionView: FC<ItemsSelectionViewProps> = ({
selectedItemId, selectedItemId,
setSelectedItem, setSelectedItem,
handleScroll, handleScroll,
onLargeBtnClick,
onSmallBtnClick,
activeScope, activeScope,
}) => { }) => {
return ( return (
@ -49,19 +45,6 @@ export const ItemsSelectionView: FC<ItemsSelectionViewProps> = ({
activeScope={activeScope} activeScope={activeScope}
/> />
</Box> </Box>
<Box
sx={{
marginTop: "20px",
alignSelf: "end",
}}
>
<StepButtonsBlock
onLargeBtnClick={onLargeBtnClick}
largeBtnText={"Добавить"}
onSmallBtnClick={onSmallBtnClick}
smallBtnText={"Отменить"}
/>
</Box>
</Box> </Box>
); );
}; };

@ -53,10 +53,11 @@ interface Props {
setSelectedTags: any; setSelectedTags: any;
selectedQuestions: any; selectedQuestions: any;
setSelectedQuestions: any; setSelectedQuestions: any;
setPageOfPipelines: any; setPageOfPipelines: () => void;
setPageOfPipelinesSteps: any; setPageOfPipelinesSteps: () => void;
setPageOfUsers: any; setPageOfUsers: () => void;
setPageOfTags: any; setPageOfTags: () => void;
setPageOfFields: () => void;
setSelectedCurrentFields: any; setSelectedCurrentFields: any;
handleCloseModal: any; handleCloseModal: any;
} }
@ -86,6 +87,7 @@ export const SwitchPages = ({
setPageOfPipelinesSteps, setPageOfPipelinesSteps,
setPageOfUsers, setPageOfUsers,
setPageOfTags, setPageOfTags,
setPageOfFields,
setSelectedCurrentFields, setSelectedCurrentFields,
handleCloseModal, handleCloseModal,
}: Props) => { }: Props) => {
@ -93,6 +95,10 @@ export const SwitchPages = ({
const [specialPage, setSpecialPage] = useState<"deleteCell" | "removeAccount" | "settingsBlock" | "accountInfo" | "amoLogin" | "">(accountInfo ? "accountInfo" : "amoLogin") const [specialPage, setSpecialPage] = useState<"deleteCell" | "removeAccount" | "settingsBlock" | "accountInfo" | "amoLogin" | "">(accountInfo ? "accountInfo" : "amoLogin")
const [openDelete, setOpenDelete] = useState<TagQuestionHC | null>(null); const [openDelete, setOpenDelete] = useState<TagQuestionHC | null>(null);
const startDeleteTagQuestion = (itemForDelete) => {
setOpenDelete(itemForDelete)
setSpecialPage("deleteCell")
}
const minifiedQuestions = useMemo( const minifiedQuestions = useMemo(
() => () =>
@ -160,20 +166,12 @@ export const SwitchPages = ({
if (openDelete.type === "question") { if (openDelete.type === "question") {
let newArray = selectedQuestions let newArray = selectedQuestions
newArray[openDelete.scope as QuestionKeys] = newArray[openDelete.scope as QuestionKeys].filter(e => e.id !== openDelete.id) newArray[openDelete.scope as QuestionKeys] = newArray[openDelete.scope as QuestionKeys].filter(e => e.id !== openDelete.id)
// let index = -1
// selectedQuestions[openDelete.scope].forEach((e, i) => {
// if (e.subTitle === openDelete.id) index = i
// })
// if (index !== -1) newArray.splice(index, 1);
// setSelectedQuestions((prevState) => ({
// ...prevState,
// [openDelete.scope]: newArray,
// }));
setSelectedQuestions(newArray); setSelectedQuestions(newArray);
setSelectedCurrentFields(selectedCurrentFields.filter(e => e.id !== openDelete.id)); setSelectedCurrentFields(selectedCurrentFields.filter(e => e.id !== openDelete.id));
} }
setOpenDelete(null); setOpenDelete(null);
closeSpecialPage();
} }
const handleNextStep = () => { const handleNextStep = () => {
@ -259,6 +257,8 @@ export const SwitchPages = ({
desc: "На этом этапе вы можете выбрать нужную воронку и ответственного за сделку", desc: "На этом этапе вы можете выбрать нужную воронку и ответственного за сделку",
toSettings: () => setSpecialPage("settingsBlock") toSettings: () => setSpecialPage("settingsBlock")
}} }}
onScroll={setPageOfPipelines}
onScrollUsers={setPageOfUsers}
/> />
), ),
}, },
@ -280,6 +280,8 @@ export const SwitchPages = ({
desc: "На этом этапе вы можете выбрать нужный этап и ответственного за сделку", desc: "На этом этапе вы можете выбрать нужный этап и ответственного за сделку",
toSettings: () => setSpecialPage("settingsBlock") toSettings: () => setSpecialPage("settingsBlock")
}} }}
onScroll={setPageOfPipelinesSteps}
onScrollUsers={setPageOfUsers}
/> />
), ),
}, },
@ -298,6 +300,7 @@ export const SwitchPages = ({
desc: "На этом этапе вы можете выбрать ответственного за сделку", desc: "На этом этапе вы можете выбрать ответственного за сделку",
toSettings: () => setSpecialPage("settingsBlock") toSettings: () => setSpecialPage("settingsBlock")
}} }}
onScrollUsers={setPageOfUsers}
/> />
), ),
}, },
@ -307,8 +310,7 @@ export const SwitchPages = ({
<AmoTags <AmoTags
tagsItems={arrayOfTags} tagsItems={arrayOfTags}
selectedTags={selectedTags} selectedTags={selectedTags}
openDelete={setOpenDelete} openDelete={startDeleteTagQuestion}
handleScroll={() => { }}
handleAddTag={handleAddTagQuestion} handleAddTag={handleAddTagQuestion}
handlePrevStep={handlePrevStep} handlePrevStep={handlePrevStep}
handleNextStep={handleNextStep} handleNextStep={handleNextStep}
@ -318,6 +320,7 @@ export const SwitchPages = ({
desc: "На этом этапе вы можете добавить теги с результатами", desc: "На этом этапе вы можете добавить теги с результатами",
toSettings: () => setSpecialPage("settingsBlock") toSettings: () => setSpecialPage("settingsBlock")
}} }}
onScroll={setPageOfTags}
/> />
), ),
}, },
@ -330,7 +333,7 @@ export const SwitchPages = ({
selectedCurrentFields={selectedCurrentFields} selectedCurrentFields={selectedCurrentFields}
questionsItems={minifiedQuestions} questionsItems={minifiedQuestions}
selectedQuestions={selectedQuestions} selectedQuestions={selectedQuestions}
openDelete={setOpenDelete} openDelete={startDeleteTagQuestion}
handleAddQuestion={handleAddTagQuestion} handleAddQuestion={handleAddTagQuestion}
handlePrevStep={handlePrevStep} handlePrevStep={handlePrevStep}
handleNextStep={handleSave} handleNextStep={handleSave}
@ -340,6 +343,7 @@ export const SwitchPages = ({
title: "Соотнесение вопросов и сущностей", title: "Соотнесение вопросов и сущностей",
toSettings: () => setSpecialPage("settingsBlock") toSettings: () => setSpecialPage("settingsBlock")
}} }}
onScroll={setPageOfFields}
/> />
), ),
}, },
@ -371,7 +375,7 @@ export const SwitchPages = ({
toBack={() => closeSpecialPage()} toBack={() => closeSpecialPage()}
setStep={(step: number) => { setStep={(step: number) => {
closeSpecialPage() closeSpecialPage()
setStep(step) setStep(step-1)
}} }}
/> />
case "amoLogin": return <AmoLogin handleNextStep={handleNextStep} /> case "amoLogin": return <AmoLogin handleNextStep={handleNextStep} />
@ -390,25 +394,3 @@ export const SwitchPages = ({
}}>{steps[step].component}</Box> }}>{steps[step].component}</Box>
} }
} }
// const S = <ModalTitle
// step={1}
// steps={2}
// isSettingsBlock={true}
// setIsSettingsBlock={setIsSettingsBlock}
// setStep={setStep}
// startRemoveAccount={() => setSpecialPage("removeAccount")}
// />
// title: accountInfo ? "Информация об аккаунте" : "Авторизация в аккаунте",
// isSettingsAvailable: false,
// component: accountInfo ? (
// <AmoAccountInfo
// handleNextStep={handleNextStep}
// accountInfo={accountInfo}
// />
// ) : (
// <AmoLogin handleNextStep={handleNextStep} />
// ),
// },

@ -12,7 +12,6 @@ type Props = {
selectedTags: SelectedTags; selectedTags: SelectedTags;
handleAddTag: (scope: QuestionKeys | TagKeys, id: string, type: "question" | "tag") => void; handleAddTag: (scope: QuestionKeys | TagKeys, id: string, type: "question" | "tag") => void;
openDelete: (data: TagQuestionHC) => void; openDelete: (data: TagQuestionHC) => void;
handleScroll: () => void;
handlePrevStep: () => void; handlePrevStep: () => void;
handleNextStep: () => void; handleNextStep: () => void;
titleProps: { titleProps: {
@ -21,6 +20,8 @@ type Props = {
desc: string; desc: string;
toSettings: () => void; toSettings: () => void;
} }
onScroll: () => void;
}; };
export const AmoTags: FC<Props> = ({ export const AmoTags: FC<Props> = ({
@ -28,9 +29,9 @@ export const AmoTags: FC<Props> = ({
selectedTags, selectedTags,
handleAddTag, handleAddTag,
openDelete, openDelete,
handleScroll,
handlePrevStep, handlePrevStep,
handleNextStep, handleNextStep,
onScroll,
titleProps, titleProps,
}) => { }) => {
const [sortedTagsItems, setSortedTagsItems] = useState<MinifiedData[] | []>(tagsItems); const [sortedTagsItems, setSortedTagsItems] = useState<MinifiedData[] | []>(tagsItems);
@ -59,14 +60,14 @@ export const AmoTags: FC<Props> = ({
return ( return (
<> <>
<Box <Box
sx={{ sx={{
height: "calc( 100% - 70px )", height: "calc( 100% - 70px )",
overflow: "auto" overflow: "auto"
}} }}
> >
<ModalTitle <ModalTitle
{...titleProps} {...titleProps}
/> />
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
@ -81,21 +82,12 @@ export const AmoTags: FC<Props> = ({
isError={sortedTagsItems.length === 0} isError={sortedTagsItems.length === 0}
constrictor={startConstrictor} constrictor={startConstrictor}
/> />
<ItemsSelectionView <ItemsSeactiveScopelectionView
items={sortedTagsItems} items={sortedTagsItems}
selectedItemId={selectedTag} selectedItemId={selectedTag}
setSelectedItem={setSelectedTag} setSelectedItem={setSelectedTag}
handleScroll={handleScroll} handleScroll={onScroll}
activeScope={activeScope} activeScope={activeScope}
onSmallBtnClick={() => {
setActiveScope(null);
setIsSelection(false);
}}
onLargeBtnClick={() => {
handleAdd();
setActiveScope(null);
setIsSelection(false);
}}
/> />
</> </>
) : ( ) : (
@ -115,10 +107,28 @@ export const AmoTags: FC<Props> = ({
alignSelf: "end", alignSelf: "end",
}} }}
> >
<StepButtonsBlock
onSmallBtnClick={handlePrevStep} {
onLargeBtnClick={handleNextStep} isSelection && activeScope !== null ?
/> <StepButtonsBlock
onLargeBtnClick={() => {
handleAdd();
setActiveScope(null);
setIsSelection(false);
}}
largeBtnText={"Добавить"}
onSmallBtnClick={() => {
setActiveScope(null);
setIsSelection(false);
}}
smallBtnText={"Отменить"}
/>
:
<StepButtonsBlock
onSmallBtnClick={handlePrevStep}
onLargeBtnClick={handleNextStep}
/>
}
</Box> </Box>
</> </>
); );

@ -57,6 +57,7 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({ isModalOpen, handleClo
setPageOfPipelinesSteps, setPageOfPipelinesSteps,
setPageOfUsers, setPageOfUsers,
setPageOfTags, setPageOfTags,
setPageOfFields,
setSelectedCurrentFields, setSelectedCurrentFields,
} = useAmoIntegration({ } = useAmoIntegration({
quizID: quiz.backendId, quizID: quiz.backendId,
@ -156,6 +157,7 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({ isModalOpen, handleClo
setPageOfPipelinesSteps={setPageOfPipelinesSteps} setPageOfPipelinesSteps={setPageOfPipelinesSteps}
setPageOfUsers={setPageOfUsers} setPageOfUsers={setPageOfUsers}
setPageOfTags={setPageOfTags} setPageOfTags={setPageOfTags}
setPageOfFields={setPageOfFields}
setSelectedCurrentFields={setSelectedCurrentFields} setSelectedCurrentFields={setSelectedCurrentFields}
handleCloseModal={handleCloseModal} handleCloseModal={handleCloseModal}
/> />

@ -15,7 +15,7 @@ import {
import { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; import { AnyTypedQuizQuestion } from "@frontend/squzanswerer";
import { UntypedQuizQuestion } from "@/model/questionTypes/shared"; import { UntypedQuizQuestion } from "@/model/questionTypes/shared";
const SIZE = 275; const SIZE = 25;
interface Props { interface Props {
isModalOpen: boolean; isModalOpen: boolean;
@ -31,6 +31,13 @@ const FCTranslate = {
"text": "номер", "text": "номер",
"address": "адрес", "address": "адрес",
} }
let isReadyGetPipeline = true;
let isReadyGetPipelineStep = true;
let isReadyGetUsers = true;
let isReadyGetTags = true;
let isReadyGetFields = true;
export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, questions }: Props) => { export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, questions }: Props) => {
const [isLoadingPage, setIsLoadingPage] = useState<boolean>(true); const [isLoadingPage, setIsLoadingPage] = useState<boolean>(true);
const [firstRules, setFirstRules] = useState<boolean>(false); const [firstRules, setFirstRules] = useState<boolean>(false);
@ -102,13 +109,13 @@ export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, que
if (gottenList !== null) { if (gottenList !== null) {
Object.keys(gottenList.QuestionID).forEach((qId) => { Object.keys(gottenList.QuestionID).forEach((qId) => {
const q = questions.find(e=>e.backendId === Number(qId)) || {} const q = questions.find(e => e.backendId === Number(qId)) || {}
gottenQuestions[key as QuestionKeys].push({ gottenQuestions[key as QuestionKeys].push({
id: qId, id: qId,
title: q.title, title: q.title,
entity: key, entity: key,
}) })
}) })
} }
@ -155,9 +162,9 @@ export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, que
useEffect(() => { useEffect(() => {
const transletedQuestions = {} const transletedQuestions = {}
Object.keys(selectedQuestions).forEach((column) => { Object.keys(selectedQuestions)?.forEach((column) => {
selectedQuestions[column].forEach((minifiedData) => { selectedQuestions[column].forEach((minifiedData) => {
const q = questions.find(e => e.backendId === Number(minifiedData.id)) || {} const q = questions.find(e => e.backendId === Number(minifiedData.id)) || {}
transletedQuestions[column] = { transletedQuestions[column] = {
...minifiedData, ...minifiedData,
title: q.title || transletedQuestions[column].title title: q.title || transletedQuestions[column].title
@ -169,115 +176,142 @@ export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, que
}, [questions]) }, [questions])
useEffect(() => { useEffect(() => {
getPipelines({ if (isReadyGetPipeline) {
page: pageOfPipelines, getPipelines({
size: SIZE, page: pageOfPipelines,
}).then(([response]) => {
if (response && response.items !== null) {
const minifiedPipelines: MinifiedData[] = [];
response.items.forEach((step) => {
minifiedPipelines.push({
id: step.AmoID.toString(),
title: step.Name,
});
});
setArrayOfPipelines((prevItems) => [...prevItems, ...minifiedPipelines]);
setPageOfPipelinesSteps(1);
}
});
}, [pageOfPipelines]);
useEffect(() => {
const oldData = pageOfPipelinesSteps === 1 ? [] : arrayOfPipelinesSteps;
if (selectedPipeline !== null)
getSteps({
page: pageOfPipelinesSteps,
size: SIZE, size: SIZE,
pipelineId: Number(selectedPipeline),
}).then(([response]) => { }).then(([response]) => {
if (response && response.items !== null) { if (response && response.items !== null) {
const minifiedSteps: MinifiedData[] = []; const minifiedPipelines: MinifiedData[] = [];
response.items.forEach((step) => { response.items.forEach((step) => {
minifiedSteps.push({ minifiedPipelines.push({
id: step.AmoID.toString(), id: step.AmoID.toString(),
title: step.Name, title: step.Name,
}); });
}); });
setArrayOfPipelinesSteps([...oldData, ...minifiedSteps]); setArrayOfPipelines((prevItems) => [...prevItems, ...minifiedPipelines]);
setPageOfPipelinesSteps(1);
} else {
isReadyGetPipeline = false
} }
}); });
}
}, [pageOfPipelines]);
useEffect(() => {
if (isReadyGetPipelineStep) {
const oldData = pageOfPipelinesSteps === 1 ? [] : arrayOfPipelinesSteps;
if (selectedPipeline !== null)
getSteps({
page: pageOfPipelinesSteps,
size: SIZE,
pipelineId: Number(selectedPipeline),
}).then(([response]) => {
if (response && response.items !== null) {
const minifiedSteps: MinifiedData[] = [];
response.items.forEach((step) => {
minifiedSteps.push({
id: step.AmoID.toString(),
title: step.Name,
});
});
setArrayOfPipelinesSteps([...oldData, ...minifiedSteps]);
} else {
isReadyGetPipelineStep = false
}
});
}
}, [selectedPipeline, pageOfPipelinesSteps]); }, [selectedPipeline, pageOfPipelinesSteps]);
useEffect(() => { useEffect(() => {
getUsers({ if (isReadyGetUsers) {
page: pageOfUsers, getUsers({
size: SIZE, page: pageOfUsers,
}).then(([response]) => { size: SIZE,
if (response && response.items !== null) { }).then(([response]) => {
const minifiedUsers: MinifiedData[] = []; if (response && response.items !== null) {
const minifiedUsers: MinifiedData[] = [];
response.items.forEach((step) => { response.items.forEach((step) => {
minifiedUsers.push({ minifiedUsers.push({
id: step.amoUserID.toString(), id: step.amoUserID.toString(),
title: step.name, title: step.name,
});
}); });
}); setArrayOfUsers((prevItems) => [...prevItems, ...minifiedUsers]);
setArrayOfUsers((prevItems) => [...prevItems, ...minifiedUsers]); } else {
} isReadyGetUsers = false
}); }
});
}
}, [pageOfUsers]); }, [pageOfUsers]);
useEffect(() => { useEffect(() => {
getTags({ if (isReadyGetTags) {
page: pageOfTags, getTags({
size: SIZE, page: pageOfTags,
}).then(([response]) => { size: SIZE,
if (response && response.items !== null) { }).then(([response]) => {
const minifiedTags: MinifiedData[] = []; if (response && response.items !== null) {
const minifiedTags: MinifiedData[] = [];
response.items.forEach((step) => { response.items.forEach((step) => {
minifiedTags.push({ minifiedTags.push({
id: step.AmoID.toString(), id: step.AmoID.toString(),
title: step.Name, title: step.Name,
entity: entity:
step.Entity === "leads" step.Entity === "leads"
? "Lead" ? "Lead"
: step.Entity === "contacts" : step.Entity === "contacts"
? "Contact" ? "Contact"
: step.Entity === "companies" : step.Entity === "companies"
? "Company" ? "Company"
: "Customer", : "Customer",
});
}); });
}); setArrayOfTags((prevItems) => [...prevItems, ...minifiedTags]);
setArrayOfTags((prevItems) => [...prevItems, ...minifiedTags]); } else {
} isReadyGetTags = false
}); }
});
}
}, [pageOfTags]); }, [pageOfTags]);
useEffect(() => { useEffect(() => {
getFields({ if (isReadyGetFields) {
page: pageOfTags, getFields({
size: SIZE, page: pageOfTags,
}).then(([response]) => { size: SIZE,
if (response && response.items !== null) { }).then(([response]) => {
const minifiedTags: MinifiedData[] = []; if (response && response.items !== null) {
const minifiedTags: MinifiedData[] = [];
response.items.forEach((field) => { response.items.forEach((field) => {
minifiedTags.push({ minifiedTags.push({
id: field.AmoID.toString(), id: field.AmoID.toString(),
title: field.Name, title: field.Name,
entity: entity:
field.Entity === "leads" field.Entity === "leads"
? "Lead" ? "Lead"
: field.Entity === "contacts" : field.Entity === "contacts"
? "Contact" ? "Contact"
: field.Entity === "companies" : field.Entity === "companies"
? "Company" ? "Company"
: "Customer", : "Customer",
});
}); });
}); setArrayOfFields((prevItems) => [...prevItems, ...minifiedTags]);
setArrayOfFields((prevItems) => [...prevItems, ...minifiedTags]); }
} });
}); } else {
isReadyGetFields = false
}
}, [pageOfFields]); }, [pageOfFields]);
useEffect(() => () => {
isReadyGetPipeline = true;
isReadyGetPipelineStep = true;
isReadyGetUsers = true;
isReadyGetTags = true;
isReadyGetFields = true;
}, [])
return { return {
isLoadingPage, isLoadingPage,
@ -300,10 +334,11 @@ export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, que
setSelectedTags, setSelectedTags,
selectedQuestions, selectedQuestions,
setSelectedQuestions, setSelectedQuestions,
setPageOfPipelines, setPageOfPipelines: () => setPageOfPipelines(old => old + 1),
setPageOfPipelinesSteps, setPageOfPipelinesSteps: () => setPageOfPipelinesSteps(old => old + 1),
setPageOfUsers, setPageOfUsers: () => setPageOfUsers(old => old + 1),
setPageOfTags, setPageOfTags: () => setPageOfTags(old => old + 1),
setPageOfFields: () => setPageOfFields(old => old + 1),
setSelectedCurrentFields, setSelectedCurrentFields,
}; };
}; };

10
src/utils/throttle.ts Normal file

@ -0,0 +1,10 @@
export function determineScrollBottom(e: any, callback: any) {
const scrollHeight = e.target.scrollHeight;
const scrollTop = e.target.scrollTop;
const clientHeight = e.target.clientHeight;
const scrolledToBottom = scrollTop / (scrollHeight - clientHeight) >= 0.9;
if (scrolledToBottom) {
callback();
}
}