frontPanel/src/pages/IntegrationsPage/IntegrationsModal/Bitrix/useBitrixIntegration.ts

447 lines
14 KiB
TypeScript
Raw Normal View History

2025-10-27 17:41:39 +00:00
import { useEffect, useState } from "react";
import { enqueueSnackbar } from "notistack";
import type { TagKeys, SelectedTags, QuestionKeys, SelectedQuestions, MinifiedData } from "./types";
import {
AccountResponse,
getIntegrationRules,
getPipelines,
getSteps,
getTags,
getUsers,
getAccount,
FieldsRule,
getFields,
2025-12-02 21:28:36 +00:00
connectBitrix,
2025-10-27 17:41:39 +00:00
} from "@/api/bitrixIntegration";
import { AnyTypedQuizQuestion } from "@frontend/squzanswerer";
import { UntypedQuizQuestion } from "@/model/questionTypes/shared";
const SIZE = 25;
interface Props {
isModalOpen: boolean;
isTryRemoveAccount: boolean;
quizID: number;
questions: (AnyTypedQuizQuestion | UntypedQuizQuestion)[]
}
const FCTranslate = {
"name": "имя",
"email": "почта",
"phone": "телефон",
"text": "номер",
"address": "адрес",
}
let isReadyGetPipeline = true;
let isReadyGetPipelineStep = true;
let isReadyGetUsers = true;
let isReadyGetTags = true;
let isReadyGetFields = true;
export const useBitrixIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, questions }: Props) => {
const [isLoadingPage, setIsLoadingPage] = useState<boolean>(true);
const [firstRules, setFirstRules] = useState<boolean>(false);
const [accountInfo, setAccountInfo] = useState<AccountResponse | null>(null);
2025-12-02 21:28:36 +00:00
const [leadFlag, setLeadFlag] = useState<boolean>(false);
2025-10-27 17:41:39 +00:00
const [arrayOfPipelines, setArrayOfPipelines] = useState<MinifiedData[]>([]);
const [arrayOfPipelinesSteps, setArrayOfPipelinesSteps] = useState<MinifiedData[]>([]);
2025-12-02 21:28:36 +00:00
const [fullArrayOfPipelinesSteps, setFullArrayOfPipelinesSteps] = useState<any[]>([]);
2025-10-27 17:41:39 +00:00
const [arrayOfUsers, setArrayOfUsers] = useState<MinifiedData[]>([]);
const [arrayOfTags, setArrayOfTags] = useState<MinifiedData[]>([]);
const [arrayOfFields, setArrayOfFields] = useState<MinifiedData[]>([]);
const [selectedPipeline, setSelectedPipeline] = useState<string | null>(null);
const [selectedPipelineStep, setSelectedPipelineStep] = useState<string | null>(null);
const [selectedDealUser, setSelectedDealPerformer] = useState<string | null>(null);
const [selectedCurrentFields, setSelectedCurrentFields] = useState<MinifiedData[]>([]);
const [questionsBackend, setQuestionsBackend] = useState<FieldsRule>({} as FieldsRule);
const [selectedTags, setSelectedTags] = useState<SelectedTags>({
Lead: [],
Contact: [],
Company: [],
Customer: [],
});
const [selectedQuestions, setSelectedQuestions] = useState<SelectedQuestions>({
2025-12-02 21:28:36 +00:00
lead: [],
company: [],
contact: [],
deal: [],
CRM_INVOICE: [],
CRM_SMART_INVOICE: [],
CRM_QUOTE: [],
CRM_REQUISITE: [],
2025-10-27 17:41:39 +00:00
});
const [pageOfPipelines, setPageOfPipelines] = useState(1);
const [pageOfPipelinesSteps, setPageOfPipelinesSteps] = useState(1);
const [pageOfUsers, setPageOfUsers] = useState(1);
const [pageOfTags, setPageOfTags] = useState(1);
const [pageOfFields, setPageOfFields] = useState(1);
2025-12-02 21:28:36 +00:00
const leadFlagHC = (s:boolean) => {
setLeadFlag(s)
};
2025-10-27 17:41:39 +00:00
const selectedPipelineHC = (id:string | null) => {
setSelectedPipeline(id);
isReadyGetPipelineStep = true;
setPageOfPipelinesSteps(1);
}
2025-12-02 21:28:36 +00:00
// useEffect(() => {
// (async () => {
// const API_URL = `https://penadigitaltech.bitrix24.ru`;
// try {
// const response = await makeRequest<void, { link: string }>({
// method: "POST",
// url: `${API_URL}/account`,
// useToken: true,
// withCredentials: true,
// body: {
// "client_bitrix_url": "penadigitaltech.bitrix24.ru"
// }
// });
// window.open(response.link, "_blank");
// } catch (nativeError) {
// return [null, `Не удалось подключить аккаунт. `];
// }
// })()
// }, [isModalOpen])
2025-10-27 17:41:39 +00:00
useEffect(() => {
const fetchAccountRules = async () => {
setIsLoadingPage(true);
const [account, accountError] = await getAccount();
if (accountError) {
if (!accountError.includes("Not Found")) enqueueSnackbar(accountError);
setAccountInfo(null);
}
if (account) {
setAccountInfo(account);
}
const [settingsResponse, rulesError] = await getIntegrationRules(quizID.toString());
if (rulesError) {
if (rulesError === "first") setFirstRules(true);
if (!rulesError.includes("Not Found") && !rulesError.includes("first")) enqueueSnackbar(rulesError);
}
if (settingsResponse) {
if (settingsResponse.PipelineID) selectedPipelineHC(settingsResponse.PipelineID.toString());
if (settingsResponse.StepID) setSelectedPipelineStep(settingsResponse.StepID.toString());
if (settingsResponse.PerformerID) setSelectedDealPerformer(settingsResponse.PerformerID.toString());
2025-12-06 06:30:01 +00:00
console.log("settingsResponse")
console.log(settingsResponse)
setLeadFlag(settingsResponse.LeadFlag)
2025-10-27 17:41:39 +00:00
if (Boolean(settingsResponse.FieldsRule) && Object.keys(settingsResponse?.FieldsRule).length > 0) {
const gottenQuestions = { ...selectedQuestions };
setQuestionsBackend(settingsResponse.FieldsRule);
for (let key in settingsResponse.FieldsRule) {
if (
settingsResponse.FieldsRule[key as QuestionKeys] !== null
) {
const gottenList = settingsResponse.FieldsRule[key as QuestionKeys];
if (gottenList !== null) {
Object.keys(gottenList.QuestionID).forEach((qId) => {
const q = questions.find(e => e.backendId === Number(qId)) || {}
if (gottenQuestions[key as QuestionKeys] === undefined) gottenQuestions[key as QuestionKeys] = []
gottenQuestions[key as QuestionKeys].push({
id: qId,
title: q.title,
entity: key,
})
})
}
if (key === "Contact") {
const MAP = settingsResponse.FieldsRule[key as QuestionKeys].ContactRuleMap
const list = []
for (let key in MAP) {
list.push({
id: key,
title: FCTranslate[key],
entity: "Contact",
2025-12-02 21:28:36 +00:00
bitrixId: MAP[key].toString(),
2025-10-27 17:41:39 +00:00
})
}
setSelectedCurrentFields(list)
}
}
}
setSelectedQuestions(gottenQuestions);
}
if (Boolean(settingsResponse.TagsToAdd) && Object.keys(settingsResponse.TagsToAdd).length > 0) {
const gottenTags = { ...selectedTags };
for (let key in settingsResponse.TagsToAdd) {
const gottenList = settingsResponse.TagsToAdd[key as TagKeys];
if (gottenList !== null && Array.isArray(gottenList)) {
gottenTags[key as TagKeys] = gottenList.map((e) => e.toString());
}
}
setSelectedTags(gottenTags);
}
setFirstRules(false);
}
setIsLoadingPage(false);
};
fetchAccountRules();
}, [isModalOpen, isTryRemoveAccount]);
useEffect(() => {
const transletedQuestions = {...selectedQuestions}
Object.keys(selectedQuestions)?.forEach((column) => {
selectedQuestions[column].forEach((minifiedData) => {
const q = questions.find(e => e.backendId === Number(minifiedData.id)) || {};
transletedQuestions[column].push({
...minifiedData,
title: q.title || transletedQuestions[column].title
})
})
})
setSelectedQuestions(transletedQuestions)
}, [questions])
useEffect(() => {
if (isReadyGetPipeline) {
getPipelines({
page: pageOfPipelines,
size: SIZE,
}).then(([response]) => {
if (response && response.items !== null) {
const minifiedPipelines: MinifiedData[] = [];
response.items.forEach((step) => {
minifiedPipelines.push({
2025-12-02 21:28:36 +00:00
id: step.bitrixID.toString(),
title: step.name || "Нет названия",
2025-10-27 17:41:39 +00:00
});
});
setArrayOfPipelines((prevItems) => [...prevItems, ...minifiedPipelines]);
setPageOfPipelinesSteps(1);
} else {
isReadyGetPipeline = false
}
});
}
}, [pageOfPipelines]);
2025-12-02 21:28:36 +00:00
useEffect(() => {
if (isReadyGetPipelineStep && selectedPipeline !== null) {
const oldData = pageOfPipelinesSteps === 1 ? [] : arrayOfPipelinesSteps;
const oldFullData = pageOfPipelinesSteps === 1 ? [] : fullArrayOfPipelinesSteps;
getSteps({
page: pageOfPipelinesSteps,
size: SIZE,
pipelineId: Number(selectedPipeline),
}).then(([response]) => {
if (response && response.items !== null) {
// Фильтруем только нужные элементы
const filteredItems = response.items.filter(item =>
item.entityID === "STATUS" ||
item.entityID === "SOURCE" ||
(typeof item.entityID === 'string' && item.entityID.startsWith("DEAL_STAGE"))
);
// Минифицируем отфильтрованные данные
const minifiedSteps: MinifiedData[] = filteredItems.map((step) => ({
id: step.bitrixID.toString(),
title: step.name,
entity: step.entityID
}));
// Обновляем массивы
setArrayOfPipelinesSteps([...oldData, ...minifiedSteps]);
setFullArrayOfPipelinesSteps([...oldFullData, ...filteredItems]);
} else {
// Если нет данных, отключаем дальнейшие запросы
isReadyGetPipelineStep = false;
}
}).catch(error => {
console.error("Ошибка при получении шагов:", error);
isReadyGetPipelineStep = false;
});
}
}, [selectedPipeline, pageOfPipelinesSteps]);
2025-10-27 17:41:39 +00:00
useEffect(() => {
if (isReadyGetUsers) {
getUsers({
page: pageOfUsers,
size: SIZE,
}).then(([response]) => {
if (response && response.items !== null) {
const minifiedUsers: MinifiedData[] = [];
response.items.forEach((step) => {
minifiedUsers.push({
2025-12-02 21:28:36 +00:00
id: step.bitrixUserID.toString(),
title: step.name || "Нет имени",
2025-10-27 17:41:39 +00:00
});
});
setArrayOfUsers((prevItems) => [...prevItems, ...minifiedUsers]);
} else {
isReadyGetUsers = false
}
});
}
}, [pageOfUsers]);
2025-12-02 21:28:36 +00:00
// useEffect(() => {
// if (isReadyGetTags) {
// getTags({
// page: pageOfTags,
// size: SIZE,
// }).then(([response]) => {
// if (response && response.items !== null) {
// const minifiedTags: MinifiedData[] = [];
// response.items.forEach((step) => {
// minifiedTags.push({
// id: step.BitrixID.toString(),
// title: step.Name,
// entity:
// step.Entity === "leads"
// ? "Lead"
// : step.Entity === "contacts"
// ? "Contact"
// : step.Entity === "companies"
// ? "Company"
// : "Customer",
// });
// });
// setArrayOfTags((prevItems) => [...prevItems, ...minifiedTags]);
// } else {
// isReadyGetTags = false
// }
// });
// }
// }, [pageOfTags]);
2025-10-27 17:41:39 +00:00
useEffect(() => {
2025-12-02 21:28:36 +00:00
if (isReadyGetFields) {
getFields({
page: pageOfFields,
size: 1000,
}).then(([response]) => {
if (response && response.items !== null) {
const minifiedTags: MinifiedData[] = [];
console.log("fields: ")
console.log(response.items)
const entityMap = {
'CRM_LEAD': 'lead',
'CRM_DEAL': 'deal',
'CRM_COMPANY': 'company',
'CRM_CONTACT': 'contact'
};
response.items.forEach((field) => {
console.log("поле: ")
console.log(field)
const entity = entityMap[field.entityID];
if (entity) {
2025-10-27 17:41:39 +00:00
minifiedTags.push({
2025-12-02 21:28:36 +00:00
id: field.bitrixID.toString(),
title: field.editFromLabel,
entity: entity,
2025-10-27 17:41:39 +00:00
});
2025-12-02 21:28:36 +00:00
}
});
setArrayOfFields((prevItems) => [...prevItems, ...minifiedTags]);
}
});
} else {
isReadyGetFields = false
}
}, [pageOfFields]);
2025-10-27 17:41:39 +00:00
useEffect(() => () => {
isReadyGetPipeline = true;
isReadyGetPipelineStep = true;
isReadyGetUsers = true;
isReadyGetTags = true;
isReadyGetFields = true;
}, [])
return {
isLoadingPage,
firstRules,
accountInfo,
arrayOfPipelines,
arrayOfPipelinesSteps,
arrayOfUsers,
arrayOfTags,
arrayOfFields,
selectedPipeline,
setSelectedPipeline: selectedPipelineHC,
selectedCurrentFields,
selectedPipelineStep,
setSelectedPipelineStep,
selectedDealUser,
setSelectedDealPerformer,
questionsBackend,
selectedTags,
setSelectedTags,
selectedQuestions,
setSelectedQuestions,
setPageOfPipelines: () => setPageOfPipelines(old => old + 1),
setPageOfPipelinesSteps: () => setPageOfPipelinesSteps(old => old + 1),
setPageOfUsers: () => setPageOfUsers(old => old + 1),
setPageOfTags: () => setPageOfTags(old => old + 1),
setPageOfFields: () => setPageOfFields(old => old + 1),
setSelectedCurrentFields,
2025-12-02 21:28:36 +00:00
leadFlag,
leadFlagHC,
fullArrayOfPipelinesSteps
2025-10-27 17:41:39 +00:00
};
};
import { makeRequest } from "@frontend/kitui";
const API_URL = `${process.env.REACT_APP_DOMAIN}/squiz/bitrix`;
export const resetBitrixTagsFields = async () => {
let success = true
//Fields
try {
await makeRequest({
method: "PATCH",
url: `${API_URL}/fields`,
});
} catch (nativeError) {
success = false
}
//Tags
try {
await makeRequest({
method: "PATCH",
url: `${API_URL}/tags`,
});
} catch (nativeError) {
success = false
}
if (success) {
enqueueSnackbar("Данные обновятся через 5-30 минут")
} else {
enqueueSnackbar("Не удалось обновить данные")
}
}