From 179be134880c42c87816cfe612bc2fc59fc67cb8 Mon Sep 17 00:00:00 2001 From: Nastya Date: Tue, 11 Jun 2024 22:52:20 +0300 Subject: [PATCH 01/11] new hard model amo --- .../IntegrationsModal/AmoCRMModal.tsx | 59 +++++++++++++++---- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/src/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal.tsx index 3d3cf7b3..0fed0ff8 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal.tsx @@ -107,9 +107,9 @@ export const AmoCRMModal: FC = ({ } if (settingsResponse) { console.log(settingsResponse); - setFirstRules(false); + setFirstRules(false); } - + }; fetchAccount(); @@ -130,12 +130,30 @@ export const AmoCRMModal: FC = ({ PipelineID: selectedPipeline, StepID: selectedStep, Fieldsrule: { - ...questionEntity + Lead: [ + { + QuestionID: { + "44300": 0, + } + } + ], + Company: [ + { + QuestionID: { + } + } + ], + Customer: [ + { + QuestionID: { + } + } + ] }, TagsToAdd: { ...tags } - }) + }) if (quizID === undefined) return if (selectedPipeline?.toString().length === 0) return enqueueSnackbar("Выберите воронку") if (selectedPipeline?.toString().length === 0) return enqueueSnackbar("Выберите этап воронки") @@ -146,7 +164,26 @@ export const AmoCRMModal: FC = ({ PipelineID: Number(selectedPipeline), StepID: Number(selectedStep), Fieldsrule: { - ...questionEntity + Lead: [ + { + QuestionID: { + "44300": 0, + } + } + ], + Company: [ + { + QuestionID: { + } + } + ], + Customer: [ + { + QuestionID: { + } + } + ] + }, TagsToAdd: { ...tags @@ -155,12 +192,12 @@ export const AmoCRMModal: FC = ({ } else { const body = { - Fieldsrule: { - ...questionEntity - }, - TagsToAdd: { - ...tags - } + Fieldsrule: { + ...questionEntity + }, + TagsToAdd: { + ...tags + } }; if (selectedDealPerformer?.toString() > 0) body.PerformerID = Number(selectedDealPerformer) if (selectedPipeline?.toString() > 0) body.PipelineID = Number(selectedPipeline) From 4354d543461063245fcac472fd06d28b99a24d1a Mon Sep 17 00:00:00 2001 From: Nastya Date: Fri, 14 Jun 2024 05:30:30 +0300 Subject: [PATCH 02/11] =?UTF-8?q?=D0=BC=D0=B8=D0=BD=D0=B8=D0=BC=D0=B0?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D0=BE=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=D1=8E=D1=89=D0=B0=D1=8F=20=D0=B0=D0=BC=D0=BE=20=D0=BC=D0=BE?= =?UTF-8?q?=D0=B4=D0=B0=D0=BB=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/integration.ts | 85 +++--- .../CustomRadioGroup/CustomRadioGroup.tsx | 8 - src/components/CustomSelect/CustomSelect.tsx | 20 +- .../AmoAccountInfo/AmoAccountInfo.tsx | 12 +- .../IntegrationsModal/AmoCRMModal.tsx | 270 ++++++++++-------- .../IntegrationsModal/AmoLogin/AmoLogin.tsx | 1 - .../AmoModalTitle/AmoModalTitle.tsx | 1 - .../AmoQuestions.tsx} | 18 +- .../Item/AnswerItem/AnswerItem.tsx | 4 + .../Item/IconBtnAdd/IconBtnAdd.tsx | 0 .../Item/Item.tsx | 6 +- .../ItemDetailsView/ItemDetailsView.tsx | 0 .../ItemsSelectionView/ItemsSelectionView.tsx | 2 - .../AmoStep6.tsx => AmoTags/AmoTags.tsx} | 38 ++- .../TagsDetailsView/TagsDetailsView.tsx | 9 +- .../DealPerformers.tsx} | 8 +- .../PipelineSteps.tsx} | 14 +- .../AmoStep2.tsx => Pipelines/Pipelines.tsx} | 12 +- .../SettingsBlock/AmoSettingsBlock.tsx | 12 +- .../SettingsBlock/SettingItem/SettingItem.tsx | 5 +- src/pages/createQuize/AvailablePrivilege.tsx | 10 - src/stores/questions/actions.ts | 4 - src/stores/results/actions.ts | 2 - src/ui_kit/CheckFastlink.tsx | 1 - src/utils/parse-error.ts | 2 +- 25 files changed, 277 insertions(+), 267 deletions(-) rename src/pages/IntegrationsPage/IntegrationsModal/{IntegrationStep7/AmoStep7.tsx => AmoQuestions/AmoQuestions.tsx} (87%) rename src/pages/IntegrationsPage/IntegrationsModal/{IntegrationStep7 => AmoQuestions}/Item/AnswerItem/AnswerItem.tsx (86%) rename src/pages/IntegrationsPage/IntegrationsModal/{IntegrationStep7 => AmoQuestions}/Item/IconBtnAdd/IconBtnAdd.tsx (100%) rename src/pages/IntegrationsPage/IntegrationsModal/{IntegrationStep7 => AmoQuestions}/Item/Item.tsx (95%) rename src/pages/IntegrationsPage/IntegrationsModal/{IntegrationStep7 => AmoQuestions}/ItemDetailsView/ItemDetailsView.tsx (100%) rename src/pages/IntegrationsPage/IntegrationsModal/{IntegrationStep7 => AmoQuestions}/ItemsSelectionView/ItemsSelectionView.tsx (97%) rename src/pages/IntegrationsPage/IntegrationsModal/{IntegrationStep6/AmoStep6.tsx => AmoTags/AmoTags.tsx} (63%) rename src/pages/IntegrationsPage/IntegrationsModal/{IntegrationStep6 => AmoTags}/TagsDetailsView/TagsDetailsView.tsx (89%) rename src/pages/IntegrationsPage/IntegrationsModal/{AmoStep4/AmoStep4.tsx => DealPerformers/DealPerformers.tsx} (87%) rename src/pages/IntegrationsPage/IntegrationsModal/{AmoStep3/AmoStep3.tsx => PipelineSteps/PipelineSteps.tsx} (86%) rename src/pages/IntegrationsPage/IntegrationsModal/{AmoStep2/AmoStep2.tsx => Pipelines/Pipelines.tsx} (86%) diff --git a/src/api/integration.ts b/src/api/integration.ts index 158c9688..0a1992dd 100644 --- a/src/api/integration.ts +++ b/src/api/integration.ts @@ -11,19 +11,20 @@ const API_URL = `${process.env.REACT_APP_DOMAIN}/squiz/amocrm`; // получение информации об аккаунте export type AccountResponse = { - ID: number; - AmoUserID: number; - AccountID: string; - AmoID: number; - Name: string; - Email: string; - Role: string; - Group: number; - Deleted: boolean; - CreatedAt: number; - Subdomain: string; - Amoiserid: number; - Country: string; + id: number; + accountID: string; + amoID: number; + name: string; + deleted: boolean; + createdAt: string; + subdomain: string; + country: string; + driveURL: string; + // AmoUiserid: number; + // Email: string; + // Role: string; + // Group: number; + // AmoUserID: number; }; export const getAccount = async (): Promise< @@ -117,18 +118,18 @@ export const getTags = async ({ //получение списка пользователей export type User = { - ID: number; - AccountID: string; - AmoID: number; - Name: string; - Email: string; - Role: string; - Group: number; - Deleted: boolean; - CreatedAt: number; - Subdomain: string; - Amoiserid: number; - Country: string; + id: number; + amoID: number; + name: string; + email: string; + role: number; + group: number; + deleted: boolean; + createdAt: string; + amoUserID: number; + + // Subdomain: string; + // AccountID: string; }; export type UsersResponse = { @@ -229,23 +230,35 @@ export const getPipelines = async ({ }; //получение настроек интеграции +type QuestionID = Record export type IntegrationRules = { - ID: number; - AccountID: number; - QuizID: number; - PerformerID: number; PipelineID: number; StepID: number; - UTMs: number[]; + PerformerID?: number; FieldsRule: { - Lead: { QuestionID: number }[]; - Contact: { ContactRuleMap: string }[]; - Company: { QuestionID: number }[]; - Customer: { QuestionID: number }[]; + Lead: [ + { + QuestionID: QuestionID; + } + ] | null, + Company: [ + { + QuestionID: QuestionID; + } + ] | null, + Customer: [ + { + QuestionID: QuestionID; + } + ] | null, }; - Deleted: boolean; - CreatedAt: number; + TagsToAdd: { + Lead: number[] | null; + Contact: number[] | null; + Company: number[] | null; + Customer: number[] | null; + } }; export const getIntegrationRules = async ( diff --git a/src/components/CustomRadioGroup/CustomRadioGroup.tsx b/src/components/CustomRadioGroup/CustomRadioGroup.tsx index f91456e7..b24b57fe 100644 --- a/src/components/CustomRadioGroup/CustomRadioGroup.tsx +++ b/src/components/CustomRadioGroup/CustomRadioGroup.tsx @@ -54,8 +54,6 @@ export const CustomRadioGroup: FC = ({ const boxRef = useRef(null); const handleChange = (event: React.ChangeEvent) => { - console.log("применился хенделчейндж") - console.log((event.target as HTMLInputElement).value) setSelectedValue((event.target as HTMLInputElement).value); setCurrentValue((event.target as HTMLInputElement).value); }; @@ -70,9 +68,6 @@ export const CustomRadioGroup: FC = ({ setPage((prevPage) => prevPage + 1); } }; - console.log(type) - console.log(items) - console.log(type === "typeQuestions" && items && items.length !== 0) useEffect(() => { if (type === "typeTags" && hasMoreItems && setTags !== undefined) { @@ -315,9 +310,6 @@ export const CustomRadioGroup: FC = ({ name="controlled-radio-buttons-group" value={currentValue} onChange={(e) => { - console.log("klick") - console.log(e.target.value) - console.log(typeof e.target.value) handleChange(e) }} > diff --git a/src/components/CustomSelect/CustomSelect.tsx b/src/components/CustomSelect/CustomSelect.tsx index 7290880a..902fd333 100644 --- a/src/components/CustomSelect/CustomSelect.tsx +++ b/src/components/CustomSelect/CustomSelect.tsx @@ -39,14 +39,16 @@ export const CustomSelect: FC = ({ const selectWidth = ref.current ? ref.current.offsetWidth : undefined; const [savedValue, setSavedValue] = useState(null); + const [userName, setUserName] = useState(""); const onSelectItem = useCallback( (event: SelectChangeEvent) => { const newValue = event.target.value.toString(); - const selectedUser = users.find((user) => user.Name === newValue); + const selectedUser = users.find((user) => user.amoUserID == Number(newValue)); + setUserName(selectedUser.name) if (selectedUser) { //для сохранения ID выбранного пользователя в стейт или конфиг... - setSavedValue(selectedUser.ID); + setSavedValue(selectedUser.id); } setCurrentValue(newValue); setSelectedItem(newValue); @@ -90,12 +92,10 @@ export const CustomSelect: FC = ({ const menuItems = useMemo(() => { if (type === "typeUsers" && users && users.length !== 0) { - console.log(type) - console.log(users) return users.map((user) => ( = ({ padding: isMobile ? "5px 0 5px 20px" : "10px 0 10px 20px", }} > - {user.Name} + {user.name} = ({ color: isMobile ? "#9A9AAF" : "#4D4D4D", }} > - {user.Email} + {user.email} = ({ color: isMobile ? "#9A9AAF" : "#4D4D4D", }} > - {user.Role} + {user.role} @@ -190,7 +190,7 @@ export const CustomSelect: FC = ({ flexGrow: 1, }} > - {currentValue || "Выберите ответственного за сделку"} + {userName || "Выберите ответственного за сделку"} = ({ gap: isMobile ? "10px" : "20px", }} > - {infoItem("Amo ID", accountInfo.AmoUserID)} - {infoItem("Имя аккаунта", accountInfo.Name)} - {infoItem("Email аккаунта", accountInfo.Email)} - {infoItemLink("ЛК в amo", `https://${accountInfo.Subdomain}.amocrm.ru/dashboard/`)} - {infoItemLink("Профиль пользователя в amo", `https://${accountInfo.Subdomain}.amocrm.ru/settings/users/`)} - {infoItem("Страна пользователя", accountInfo.Country)} + {infoItem("Amo ID", accountInfo.amoUserID)} + {infoItem("Имя аккаунта", accountInfo.name)} + {infoItem("Email аккаунта", accountInfo.email)} + {infoItemLink("ЛК в amo", `https://${accountInfo.subdomain}.amocrm.ru/dashboard/`)} + {infoItemLink("Профиль пользователя в amo", `https://${accountInfo.subdomain}.amocrm.ru/settings/users/`)} + {infoItem("Страна пользователя", accountInfo.country)} = ({ const [isRemoveAccount, setIsRemoveAccount] = useState(false); const [firstRules, setFirstRules] = useState(false); - const [accountInfo, setAccountInfo] = useState(null); - const [selectedPipelinePerformer, setSelectedPipelinePerformer] = useState< - string | null - >(null); - const [selectedPipeline, setSelectedPipeline] = useState(null); - const [selectedStepsPerformer, setSelectedStepsPerformer] = useState< - string | null - >(null); - const [selectedStep, setSelectedStep] = useState(null); - const [selectedDealPerformer, setSelectedDealPerformer] = useState< - string | null - >(null); + + const [arrayOfPipelines, setArrayOfPipelines] = useState([]); + const [arrayOfPipelinesSteps, setArrayOfPipelinesSteps] = useState([]); + const [arrayOfUsers, setArrayOfUsers] = useState([]); + const [arrayOfTags, setArrayOfTags] = useState([]); + + const [selectedPipeline, setSelectedPipeline] = useState(null); + const [selectedPipelineStep, setSelectedPipelineStep] = useState(null); + const [selectedDealPerformer, setSelectedDealPerformer] = useState(null); + + const [questionEntityBackend, setQuestionEntityBackend] = useState({}); const [questionEntity, setQuestionEntity] = useState({ Lead: [], - Contact: [], Company: [], Customer: [], }); @@ -82,8 +83,6 @@ export const AmoCRMModal: FC = ({ Company: [], Customer: [], }); - console.log(questionEntity) - console.log(tags) useEffect(() => { if (isModalOpen && quizID !== undefined && !isRemoveAccount) { @@ -106,16 +105,78 @@ export const AmoCRMModal: FC = ({ if (!error.includes("Not Found") && !error.includes("first")) enqueueSnackbar(error); } if (settingsResponse) { - console.log(settingsResponse); + if (settingsResponse.PipelineID) setSelectedPipeline(settingsResponse.PipelineID) + if (settingsResponse.StepID) setSelectedPipelineStep(settingsResponse.StepID) + if (settingsResponse.PerformerID) setSelectedDealPerformer(settingsResponse.PerformerID) + if (Boolean(settingsResponse.FieldsRule) && + Object.keys(settingsResponse.FieldsRule).length > 0) { + const newRules = { ...questionEntity } + setQuestionEntityBackend(settingsResponse.FieldsRule) + for (let key in settingsResponse.FieldsRule) { + if (settingsResponse.FieldsRule[key] !== null && Array.isArray(settingsResponse.FieldsRule[key])) { + const gottenList = Object.keys(settingsResponse.FieldsRule[key][0].QuestionID) + newRules[key] = gottenList + } + } + setQuestionEntity(newRules) + } + if (Boolean(settingsResponse.TagsToAdd) && + Object.keys(settingsResponse.TagsToAdd).length > 0) { + const newRules = { ...tags } + for (let key in settingsResponse.TagsToAdd) { + const gottenList = settingsResponse.TagsToAdd[key] + if (gottenList !== null && Array.isArray(gottenList)) { + newRules[key] = gottenList + } + } + setTags(newRules) + } setFirstRules(false); } }; + getTags({ + page: 1, + size: 9999, + }).then(([response]) => { + if (response && response.items !== null) { + setArrayOfTags(response.items); + } + }); + getUsers({ + page: 1, + size: 9999, + }).then(([response]) => { + if (response && response.items !== null) { + setArrayOfUsers(response.items); + } + }); + getPipelines({ + page: 1, + size: 9999, + }).then(([response]) => { + if (response && response.items !== null) { + setArrayOfPipelines(response.items); + } + }) + fetchAccount(); fetchRules(); } }, [isModalOpen, isRemoveAccount]); + useEffect(() => { + if (selectedPipeline !== null) + getSteps({ + page: 1, + size: 9999, + pipelineId: selectedPipeline, + }).then(([response]) => { + if (response && response.items !== null) { + setArrayOfPipelinesSteps(response.items); + } + }); + }, [selectedPipeline]) const handleNextStep = () => { setStep((prevState) => prevState + 1); @@ -126,88 +187,47 @@ export const AmoCRMModal: FC = ({ const handleSave = () => { console.log("На отправку") console.log({ - PerformerID: selectedDealPerformer, - PipelineID: selectedPipeline, - StepID: selectedStep, - Fieldsrule: { - Lead: [ - { - QuestionID: { - "44300": 0, - } - } - ], - Company: [ - { - QuestionID: { - } - } - ], - Customer: [ - { - QuestionID: { - } - } - ] - }, - TagsToAdd: { - ...tags - } + PipelineID: Number(selectedPipeline), + StepID: Number(selectedPipelineStep), + PerformerID: Number(selectedDealPerformer), + FieldsRule: questionEntity, + TagsToAdd: tags }) - if (quizID === undefined) return - if (selectedPipeline?.toString().length === 0) return enqueueSnackbar("Выберите воронку") - if (selectedPipeline?.toString().length === 0) return enqueueSnackbar("Выберите этап воронки") + if (quizID === undefined) return + if (selectedPipeline === null) return enqueueSnackbar("Выберите воронку") + if (selectedPipeline === null) return enqueueSnackbar("Выберите этап воронки") - if (firstRules) { - setIntegrationRules(quizID.toString(), { - PerformerID: Number(selectedDealPerformer), - PipelineID: Number(selectedPipeline), - StepID: Number(selectedStep), - Fieldsrule: { - Lead: [ - { - QuestionID: { - "44300": 0, - } - } - ], - Company: [ - { - QuestionID: { - } - } - ], - Customer: [ - { - QuestionID: { - } - } - ] - - }, - TagsToAdd: { - ...tags - } - }) - } else { - const body = { - - Fieldsrule: { - ...questionEntity - }, - TagsToAdd: { - ...tags - } - }; - if (selectedDealPerformer?.toString() > 0) body.PerformerID = Number(selectedDealPerformer) - if (selectedPipeline?.toString() > 0) body.PipelineID = Number(selectedPipeline) - if (selectedStep?.toString() > 0) body.StepID = Number(selectedStep) - - updateIntegrationRules(quizID.toString(), body) + const body = { + PipelineID: Number(selectedPipeline), + StepID: Number(selectedPipelineStep), + PerformerID: Number(selectedDealPerformer), + FieldsRule: questionEntityBackend, + TagsToAdd: tags } - // handleCloseModal(); - // setStep(1); + + for (let key in questionEntityBackend) { + if (key !== "Contact") { + + if (body.FieldsRule[key] === null) body.FieldsRule[key] = [{ "QuestionID": {} }] + console.log(key) + console.log(questionEntity) + questionEntity[key].forEach((id) => { + body.FieldsRule[key][0].QuestionID[id] = 0 + }) + } + } + + console.log(body) + + if (firstRules) { + setIntegrationRules(quizID.toString(), body) + } else { + updateIntegrationRules(quizID.toString(), body) + } + + handleCloseModal(); + setStep(1); }; const steps = useMemo( () => [ @@ -229,12 +249,11 @@ export const AmoCRMModal: FC = ({ title: "Выбор воронки", isSettingsAvailable: true, component: ( - @@ -244,13 +263,13 @@ export const AmoCRMModal: FC = ({ title: "Выбор этапа воронки", isSettingsAvailable: true, component: ( - ), @@ -259,7 +278,7 @@ export const AmoCRMModal: FC = ({ title: "Сделка", isSettingsAvailable: true, component: ( - = ({ title: "Добавление тегов", isSettingsAvailable: true, component: ( - ), }, @@ -283,7 +303,7 @@ export const AmoCRMModal: FC = ({ title: "Соотнесение вопросов и сущностей", isSettingsAvailable: true, component: ( - = ({ [ accountInfo, questionEntity, - selectedPipelinePerformer, selectedPipeline, - selectedStepsPerformer, - selectedStep, + selectedPipelineStep, selectedDealPerformer, tags, ], @@ -308,7 +326,7 @@ export const AmoCRMModal: FC = ({ const stepTitles = steps.map((step) => step.title); //Если нет контекста квиза, то и делать на этой страничке нечего - if (quizID === undefined) redirect("/list") + if (quizID === undefined) return redirect("/list") return ( = ({ stepTitles={stepTitles} setIsSettingsBlock={setIsSettingsBlock} setStep={setStep} - selectedDealPerformer={selectedDealPerformer} - selectedFunnelPerformer={selectedPipelinePerformer} - selectedFunnel={selectedPipeline} - selectedStagePerformer={selectedStepsPerformer} - selectedStage={selectedStep} + selectedDealPerformer={arrayOfUsers.find(p => p.amoUserID == selectedDealPerformer)?.name || null} + selectedFunnel={arrayOfPipelines.find(p => selectedPipeline)?.Name || null} + selectedStage={arrayOfPipelinesSteps.find(p => selectedPipelineStep)?.Name || null} questionEntity={questionEntity} tags={tags} /> diff --git a/src/pages/IntegrationsPage/IntegrationsModal/AmoLogin/AmoLogin.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoLogin/AmoLogin.tsx index 9682bbef..7e9bafa0 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/AmoLogin/AmoLogin.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoLogin/AmoLogin.tsx @@ -27,7 +27,6 @@ export const AmoLogin: FC = ({ handleNextStep }) => { const isMobile = useMediaQuery(theme.breakpoints.down(600)); const onAmoClick = async () => { - console.log("Amo click"); const [url, error] = await connectAmo(); if (url && !error) { window.open(url, "_blank"); diff --git a/src/pages/IntegrationsPage/IntegrationsModal/AmoModalTitle/AmoModalTitle.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoModalTitle/AmoModalTitle.tsx index d155e105..5e31fe85 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/AmoModalTitle/AmoModalTitle.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoModalTitle/AmoModalTitle.tsx @@ -24,7 +24,6 @@ export const AmoModalTitle: FC = ({ const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); - console.log(isSettingsBlock) const handleClick = useCallback(async () => { if (isSettingsBlock) { startRemoveAccount(); diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/AmoStep7.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/AmoQuestions.tsx similarity index 87% rename from src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/AmoStep7.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/AmoQuestions.tsx index 53ddd81f..55807220 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/AmoStep7.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/AmoQuestions.tsx @@ -23,7 +23,7 @@ type Props = { questions: AllTypesQuestion[]; }; -export const AmoStep7: FC = ({ +export const AmoQuestions: FC = ({ handlePrevStep, handleNextStep, questionEntity, @@ -56,16 +56,20 @@ export const AmoStep7: FC = ({ [], ); const translatedQuestionEntity = useMemo(() => { - const translated = {} as TQuestionEntity; + const translated = { + + } as TQuestionEntity; for (let key in questionEntity) { - translated[key] = questionEntity[key].map((id) => - questions.find((q) => q.backendId === Number(id))?.title || id - ) + if (questionEntity[key] !== "Contact") { + console.log(translated) + console.log(translated[key]) + console.log(questionEntity) + translated[key] = questionEntity[key].map((id) => + questions.find((q) => q.backendId === Number(id))?.title || id) + } } - console.log("questionEntity", questionEntity) - console.log("translated", translated) return translated }, [questionEntity], diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/Item/AnswerItem/AnswerItem.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/Item/AnswerItem/AnswerItem.tsx similarity index 86% rename from src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/Item/AnswerItem/AnswerItem.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/Item/AnswerItem/AnswerItem.tsx index f4082034..a5d3d780 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/Item/AnswerItem/AnswerItem.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/Item/AnswerItem/AnswerItem.tsx @@ -21,6 +21,8 @@ export const AnswerItem: FC = ({ fieldName, fieldValue }) => { fontSize: "14px", fontWeight: 500, color: theme.palette.grey3.main, + textOverflow: "ellipsis", + overflow: "hidden" }} > {fieldName} @@ -30,6 +32,8 @@ export const AnswerItem: FC = ({ fieldName, fieldValue }) => { fontSize: "14px", fontWeight: 400, color: theme.palette.grey3.main, + textOverflow: "ellipsis", + overflow: "hidden" }} > {fieldValue} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/Item/IconBtnAdd/IconBtnAdd.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/Item/IconBtnAdd/IconBtnAdd.tsx similarity index 100% rename from src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/Item/IconBtnAdd/IconBtnAdd.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/Item/IconBtnAdd/IconBtnAdd.tsx diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/Item/Item.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/Item/Item.tsx similarity index 95% rename from src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/Item/Item.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/Item/Item.tsx index d4714b4c..a769ee90 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/Item/Item.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/Item/Item.tsx @@ -9,11 +9,9 @@ type ItemProps = { onAddBtnClick: () => void; data: TQuestionEntity | TTags; }; -export const Item: FC = ({ title, onAddBtnClick, data }) => { +export const Item: FC = ({ title, onAddBtnClick, data, tagsNamesList }) => { const theme = useTheme(); - console.log("title") - console.log(data) const titleDictionary = { Company: "Компания", Lead: "Сделка", @@ -53,7 +51,7 @@ export const Item: FC = ({ title, onAddBtnClick, data }) => { ))} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/ItemDetailsView/ItemDetailsView.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemDetailsView/ItemDetailsView.tsx similarity index 100% rename from src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/ItemDetailsView/ItemDetailsView.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemDetailsView/ItemDetailsView.tsx diff --git a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/ItemsSelectionView/ItemsSelectionView.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemsSelectionView/ItemsSelectionView.tsx similarity index 97% rename from src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/ItemsSelectionView/ItemsSelectionView.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemsSelectionView/ItemsSelectionView.tsx index 8ae24662..f79ff169 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/IntegrationStep7/ItemsSelectionView/ItemsSelectionView.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemsSelectionView/ItemsSelectionView.tsx @@ -27,8 +27,6 @@ export const ItemsSelectionView: FC = ({ parentTags, setTags }) => { - console.log("items тегов") - console.log(items) return ( void; handlePrevStep: () => void; tagsNames: TTags; - setTagsNames: Dispatch>; + setIdTags: Dispatch>; + arrayOfTags: TTags[] }; -export const AmoStep6: FC = ({ +export const AmoTags: FC = ({ handleNextStep, handlePrevStep, tagsNames, - setTagsNames + setIdTags, + arrayOfTags, }) => { const theme = useTheme(); const [isSelection, setIsSelection] = useState(false); - const [activeItem, setActiveItem] = useState(null); + const [activeTag, setActiveItem] = useState(null); const [selectedValue, setSelectedValue] = useState(null); const [tags, setTags] = useState([]); + const [tagsNamesList, setTagsNamesList] = useState>({ + Lead: [], + Contact: [], + Company: [], + Customer: [], + }); const handleAdd = useCallback(() => { - if (!activeItem || !selectedValue) return; + if (!activeTag || !selectedValue) return; - setTagsNames((prevState) => ({ + setIdTags((prevState) => ({ ...prevState, - [activeItem]: [...prevState[activeItem as TagKeys], Number(selectedValue)], + [activeTag]: [...prevState[activeTag as TagKeys], Number(selectedValue)], })); - }, [activeItem, setTagsNames, selectedValue]); - - const items = useMemo( - () => ["#тег с результатом 1", "#еще один тег с результатом 2", "#тег"], - [], - ); + setTagsNamesList((prevState) => ({ + ...prevState, + [activeTag]: [...prevState[activeTag as TagKeys], arrayOfTags.find((tag) => tag.AmoID == selectedValue).Name], + })); + }, [activeTag, setIdTags, selectedValue]); return ( = ({ /> ) : ( void; @@ -10,6 +10,7 @@ type TagsDetailsViewProps = { handleNextStep: () => void; tagsNames: TTags; setActiveItem: (value: string | null) => void; + tagsNamesList: Record }; export const TagsDetailsView: FC = ({ @@ -18,6 +19,7 @@ export const TagsDetailsView: FC = ({ tagsNames, setActiveItem, setIsSelection, + tagsNamesList, }) => { const theme = useTheme(); @@ -71,8 +73,9 @@ export const TagsDetailsView: FC = ({ {tagsNames && Object.keys(tagsNames).map((item) => ( { setIsSelection(true); setActiveItem(item); diff --git a/src/pages/IntegrationsPage/IntegrationsModal/AmoStep4/AmoStep4.tsx b/src/pages/IntegrationsPage/IntegrationsModal/DealPerformers/DealPerformers.tsx similarity index 87% rename from src/pages/IntegrationsPage/IntegrationsModal/AmoStep4/AmoStep4.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/DealPerformers/DealPerformers.tsx index 5f67d933..37fcdce4 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/AmoStep4/AmoStep4.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/DealPerformers/DealPerformers.tsx @@ -3,14 +3,14 @@ import { FC } from "react"; import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; import { CustomSelect } from "../../../../components/CustomSelect/CustomSelect"; -type AmoStep4Props = { +type Props = { handlePrevStep: () => void; handleNextStep: () => void; - selectedDealPerformer: string | null; - setSelectedDealPerformer: (value: string | null) => void; + selectedDealPerformer: number | null; + setSelectedDealPerformer: (value: number | null) => void; }; -export const AmoStep4: FC = ({ +export const DealPerformers: FC = ({ handlePrevStep, handleNextStep, selectedDealPerformer, diff --git a/src/pages/IntegrationsPage/IntegrationsModal/AmoStep3/AmoStep3.tsx b/src/pages/IntegrationsPage/IntegrationsModal/PipelineSteps/PipelineSteps.tsx similarity index 86% rename from src/pages/IntegrationsPage/IntegrationsModal/AmoStep3/AmoStep3.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/PipelineSteps/PipelineSteps.tsx index e453f173..387f7c80 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/AmoStep3/AmoStep3.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/PipelineSteps/PipelineSteps.tsx @@ -4,17 +4,17 @@ import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; import { CustomSelect } from "../../../../components/CustomSelect/CustomSelect"; import { CustomRadioGroup } from "../../../../components/CustomRadioGroup/CustomRadioGroup"; -type AmoStep3Props = { +type Props = { handlePrevStep: () => void; handleNextStep: () => void; - selectedStepsPerformer: string | null; - setSelectedStepsPerformer: (value: string | null) => void; - selectedStep: string | null; - setSelectedStep: (value: string | null) => void; - pipelineId: string | null; + selectedStepsPerformer: number | null; + setSelectedStepsPerformer: (value: number | null) => void; + selectedStep: number | null; + setSelectedStep: (value: number | null) => void; + pipelineId: number | null; }; -export const AmoStep3: FC = ({ +export const PipelineSteps: FC = ({ handlePrevStep, handleNextStep, selectedStepsPerformer, diff --git a/src/pages/IntegrationsPage/IntegrationsModal/AmoStep2/AmoStep2.tsx b/src/pages/IntegrationsPage/IntegrationsModal/Pipelines/Pipelines.tsx similarity index 86% rename from src/pages/IntegrationsPage/IntegrationsModal/AmoStep2/AmoStep2.tsx rename to src/pages/IntegrationsPage/IntegrationsModal/Pipelines/Pipelines.tsx index 8633b783..9c786a2d 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/AmoStep2/AmoStep2.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/Pipelines/Pipelines.tsx @@ -4,17 +4,17 @@ import { StepButtonsBlock } from "../StepButtonsBlock/StepButtonsBlock"; import { CustomSelect } from "../../../../components/CustomSelect/CustomSelect"; import { CustomRadioGroup } from "../../../../components/CustomRadioGroup/CustomRadioGroup"; -type AmoStep2Props = { +type Props = { handlePrevStep: () => void; handleNextStep: () => void; - selectedPipelinePerformer: string | null; - setSelectedPipelinePerformer: (value: string | null) => void; - selectedPipeline: string | null; - setSelectedPipeline: (value: string | null) => void; + selectedPipelinePerformer: number | null; + setSelectedPipelinePerformer: (value: number | null) => void; + selectedPipeline: number | null; + setSelectedPipeline: (value: number | null) => void; }; -export const AmoStep2: FC = ({ +export const Pipelines: FC = ({ handlePrevStep, handleNextStep, selectedPipelinePerformer, diff --git a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/AmoSettingsBlock.tsx b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/AmoSettingsBlock.tsx index 7cc2211f..6d4da461 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/AmoSettingsBlock.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/AmoSettingsBlock.tsx @@ -8,10 +8,8 @@ type AmoSettingsBlockProps = { stepTitles: string[]; setStep: (value: number) => void; setIsSettingsBlock: (value: boolean) => void; - selectedFunnelPerformer: string | null; - selectedFunnel: string | null; - selectedStagePerformer: string | null; - selectedStage: string | null; + selectedFunnel: number | null; + selectedStage: number | null; selectedDealPerformer: string | null; questionEntity: TQuestionEntity; tags: TTags; @@ -21,9 +19,7 @@ export const AmoSettingsBlock: FC = ({ stepTitles, setStep, setIsSettingsBlock, - selectedFunnelPerformer, selectedFunnel, - selectedStagePerformer, selectedDealPerformer, selectedStage, questionEntity, @@ -61,10 +57,8 @@ export const AmoSettingsBlock: FC = ({ title={title} setIsSettingsBlock={setIsSettingsBlock} setStep={setStep} - selectedFunnelPerformer={selectedFunnelPerformer} - selectedFunnel={selectedFunnel} - selectedStagePerformer={selectedStagePerformer} selectedDealPerformer={selectedDealPerformer} + selectedFunnel={selectedFunnel} selectedStage={selectedStage} questionEntity={questionEntity} tags={tags} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx index 82f0ac12..8c18246e 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx @@ -35,7 +35,6 @@ export const SettingItem: FC = ({ }) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); - if (step === 0) { return; } @@ -44,7 +43,7 @@ export const SettingItem: FC = ({ if (step === 1) { return ( <> - + ); @@ -52,7 +51,7 @@ export const SettingItem: FC = ({ if (step === 2) { return ( <> - + ); diff --git a/src/pages/createQuize/AvailablePrivilege.tsx b/src/pages/createQuize/AvailablePrivilege.tsx index c1a0e905..3ee17219 100644 --- a/src/pages/createQuize/AvailablePrivilege.tsx +++ b/src/pages/createQuize/AvailablePrivilege.tsx @@ -72,16 +72,6 @@ export default function AvailablePrivilege() { ); const currentDate = moment(); - console.log(quizUnlimDays); - console.log(moment()); - console.log( - moment( - moment(userPrivileges?.quizUnlimTime?.created_at).add( - quizUnlimTime, - "days", - ), - ), - ); return ( q.type), - ); }; const removeQuestion = (questionId: string) => diff --git a/src/stores/results/actions.ts b/src/stores/results/actions.ts index ca612c50..8641159f 100644 --- a/src/stores/results/actions.ts +++ b/src/stores/results/actions.ts @@ -110,7 +110,6 @@ export const ExportResults = async ( return; } - console.log(typeof data); const blob = new Blob([data as BlobPart], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8", @@ -118,7 +117,6 @@ export const ExportResults = async ( const link = document.createElement("a"); link.href = window.URL.createObjectURL(data as Blob); - console.log(link); link.download = `report_${new Date().getTime()}.xlsx`; link.click(); }; diff --git a/src/ui_kit/CheckFastlink.tsx b/src/ui_kit/CheckFastlink.tsx index 535d0ee9..d53e113c 100644 --- a/src/ui_kit/CheckFastlink.tsx +++ b/src/ui_kit/CheckFastlink.tsx @@ -28,7 +28,6 @@ export function CheckFastlink() { const [discounts, setDiscounts] = useState([]); const [askToChange, setAskToChange] = useState(false); const [promocode, setPromocode] = useState(""); - console.log(user.userAccount, user.customerAccount); useEffect(() => { const get = async () => { if (!user.userId) { diff --git a/src/utils/parse-error.ts b/src/utils/parse-error.ts index a76873e0..a27cbee0 100644 --- a/src/utils/parse-error.ts +++ b/src/utils/parse-error.ts @@ -25,7 +25,7 @@ const translateMessage: Record = { export const parseAxiosError = (nativeError: unknown): [string, number?] => { const error = nativeError as AxiosError; -console.log(error) +console.error(error) if (process.env.NODE_ENV !== "production") console.error(error); if (error.message === "Failed to fetch") return ["Ошибка сети"]; From dcb254e8e4bba3d97fcdf624297b54f5a437114f Mon Sep 17 00:00:00 2001 From: Nastya Date: Sat, 15 Jun 2024 08:00:58 +0300 Subject: [PATCH 03/11] =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B0=D0=B2=D0=B0?= =?UTF-8?q?=D0=B5=D0=BC=D1=8B=D0=B5=20=D1=82=D0=B8=D0=BF=D1=8B=20=D0=B2=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D1=8B=20?= =?UTF-8?q?=D0=B0=D0=BC=D0=BE=20=D0=BC=D0=BE=D0=B4=D0=B0=D0=BB=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/integration.ts | 5 - .../CustomRadioGroup/CustomRadioGroup.tsx | 281 +++--------------- src/components/CustomSelect/CustomSelect.tsx | 117 +++----- .../IntegrationsModal/AmoCRMModal.tsx | 266 +++++++---------- .../AmoQuestions/AmoQuestions.tsx | 95 ++---- .../ItemDetailsView/ItemDetailsView.tsx | 20 +- .../ItemsSelectionView/ItemsSelectionView.tsx | 34 +-- .../IntegrationsModal/AmoTags/AmoTags.tsx | 85 +++--- .../TagsDetailsView/TagsDetailsView.tsx | 25 +- .../DealPerformers/DealPerformers.tsx | 13 +- .../PipelineSteps/PipelineSteps.tsx | 26 +- .../IntegrationsModal/Pipelines/Pipelines.tsx | 24 +- .../SettingsBlock/AmoSettingsBlock.tsx | 24 +- .../SettingsBlock/SettingItem/SettingItem.tsx | 30 +- .../IntegrationsModal/types.ts | 11 + .../IntegrationsModal/useAmoIntegration.ts | 250 ++++++++++++++++ 16 files changed, 602 insertions(+), 704 deletions(-) create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/types.ts create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/useAmoIntegration.ts diff --git a/src/api/integration.ts b/src/api/integration.ts index 0a1992dd..a23fd89a 100644 --- a/src/api/integration.ts +++ b/src/api/integration.ts @@ -20,11 +20,6 @@ export type AccountResponse = { subdomain: string; country: string; driveURL: string; - // AmoUiserid: number; - // Email: string; - // Role: string; - // Group: number; - // AmoUserID: number; }; export const getAccount = async (): Promise< diff --git a/src/components/CustomRadioGroup/CustomRadioGroup.tsx b/src/components/CustomRadioGroup/CustomRadioGroup.tsx index b24b57fe..f7ba0a8c 100644 --- a/src/components/CustomRadioGroup/CustomRadioGroup.tsx +++ b/src/components/CustomRadioGroup/CustomRadioGroup.tsx @@ -1,172 +1,61 @@ import * as React from "react"; -import { FC, useEffect, useMemo, useRef, useState } 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 { FC, useMemo } from "react"; import CheckboxIcon from "@icons/Checkbox"; -import { Typography, useMediaQuery, useTheme } from "@mui/material"; import { - getPipelines, - getSteps, - getTags, - PaginationRequest, - Pipeline, - Step, - Tag, -} from "@api/integration"; -import type { TagQuestionObject } from "@/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal" + SelectChangeEvent, + Typography, + useTheme, + Box, + FormControlLabel, + RadioGroup, + Radio, +} from "@mui/material"; + +type Items = { + id: string; + title: string; + subTitle?: string; +} type CustomRadioGroupProps = { - type?: string; - selectedValue: string | null; - setSelectedValue: (value: string | null) => void; - pipelineId?: number | null; - items: TagQuestionObject[] - tags: Tag[] - setTags?: (setValueFunc: (value: Tag[]) => Tag[]) => void; + items: Items[] | []; + selectedItemId?: string | null; + setSelectedItem: (value: string | null) => void; + handleScroll: () => void; }; -const SIZE = 25; - export const CustomRadioGroup: FC = ({ - type, - selectedValue, - setSelectedValue, - pipelineId, items, - tags = [], - setTags, + selectedItemId = "", + setSelectedItem, + handleScroll, }) => { const theme = useTheme(); - const isMobile = useMediaQuery(theme.breakpoints.down(500)); + const currentItem = useMemo(() => { + if (selectedItemId !== null && selectedItemId.length > 0) { + return items.find(item => item.id === selectedItemId) || null + } + return null; + }, [selectedItemId, items]) - const [currentValue, setCurrentValue] = useState( - selectedValue, - ); - const [page, setPage] = useState(1); - const [isLoading, setIsLoading] = useState(false); - - const [steps, setSteps] = useState([]); - const [pipelines, setPipelines] = useState([]); - const [hasMoreItems, setHasMoreItems] = useState(true); - const boxRef = useRef(null); - - const handleChange = (event: React.ChangeEvent) => { - setSelectedValue((event.target as HTMLInputElement).value); - setCurrentValue((event.target as HTMLInputElement).value); - }; - - const handleScroll = (e: React.UIEvent) => { + const onScroll = React.useCallback((e: React.UIEvent) => { const scrollHeight = e.currentTarget.scrollHeight; const scrollTop = e.currentTarget.scrollTop; const clientHeight = e.currentTarget.clientHeight; const scrolledToBottom = scrollTop / (scrollHeight - clientHeight) > 0.9; - if (scrolledToBottom && !isLoading && hasMoreItems) { - setPage((prevPage) => prevPage + 1); + if (scrolledToBottom) { + handleScroll(); } - }; + }, []); - useEffect(() => { - if (type === "typeTags" && hasMoreItems && setTags !== undefined) { - setIsLoading(true); - const pagination: PaginationRequest = { - page: page, - size: SIZE, - }; - getTags(pagination).then(([response]) => { - if (response && response.items !== null) { - setTags((prevItems:Tag[]) => [...prevItems, ...response.items]); - if (response.items.length < SIZE) { - setHasMoreItems(false); - } - } - setIsLoading(false); - }); - } - if (type === "typeSteps" && hasMoreItems && pipelineId) { - setIsLoading(true); - const pagination: PaginationRequest & { pipelineId: number } = { - page: page, - size: SIZE, - pipelineId: pipelineId, - }; - getSteps(pagination).then(([response]) => { - if (response && response.items !== null) { - setSteps((prevItems) => [...prevItems, ...response.items]); - if (response.items.length < SIZE) { - setHasMoreItems(false); - } - } - setIsLoading(false); - }); - } - if (type === "typePipelines" && hasMoreItems) { - setIsLoading(true); - const pagination: PaginationRequest = { - page: page, - size: SIZE, - }; - getPipelines(pagination).then(([response]) => { - if (response && response.items !== null) { - setPipelines((prevItems) => [...prevItems, ...response.items]); - if (response.items.length < SIZE) { - setHasMoreItems(false); - } - } - setIsLoading(false); - }); - } - }, [page, type, hasMoreItems, pipelineId]); const formControlLabels = useMemo(() => { - if (type === "typeTags" && tags && tags.length !== 0) { - return tags.map((item) => ( - - } - icon={} - /> - } - label={ - - - {item.Name} - - {item.Entity} - - } - labelPlacement={"start"} - /> - )); - } - if (type === "typeSteps" && steps && steps.length !== 0) { - return steps.map((step) => ( - + = ({ borderRadius: "12px", margin: 0, backgroundColor: - currentValue === step.Name + currentItem?.id === item.id ? theme.palette.background.default : theme.palette.common.white, }} - value={step.AmoID} + value={item.id} control={ = ({ icon={} /> } - label={step.Name} + label={item.title} labelPlacement={"start"} /> - )); - } - if (type === "typePipelines" && pipelines && pipelines.length !== 0) { - return pipelines.map((pipeline) => ( - .MuiTypography-root": { - width: "200px", - overflow: "hidden", - textOverflow: "ellipsis" - } - }} - value={pipeline.AmoID} - control={ - - } - icon={} - /> - } - label={pipeline.Name} - labelPlacement={"start"} - /> - )); - } - if (type === "typeQuestions" && items && items.length !== 0) { - return items.map(({ backendId, title }) => ( - .MuiTypography-root": { - width: "200px", - overflow: "hidden", - textOverflow: "ellipsis" - } - }} - value={Number(backendId)} - control={ - - } - icon={} - /> - } - label={title} - labelPlacement={"start"} - /> - )); + ) } return ( = ({ Нет элементов ); - }, [tags, steps, currentValue, type, pipelines]); + }, [items]); return ( = ({ { - handleChange(e) - }} + value={setSelectedItem} + onChange={({ target }: SelectChangeEvent) => setSelectedItem(target.value)} + onScroll={onScroll} > {formControlLabels} diff --git a/src/components/CustomSelect/CustomSelect.tsx b/src/components/CustomSelect/CustomSelect.tsx index 902fd333..929ed823 100644 --- a/src/components/CustomSelect/CustomSelect.tsx +++ b/src/components/CustomSelect/CustomSelect.tsx @@ -1,3 +1,6 @@ + +import * as React from "react"; +import { FC, useCallback, useMemo, useRef, useState } from "react"; import { Avatar, MenuItem, @@ -6,96 +9,64 @@ import { Typography, useMediaQuery, useTheme, + Box, } from "@mui/material"; -import Box from "@mui/material/Box"; -import * as React from "react"; -import { FC, useCallback, useEffect, useMemo, useRef, useState } from "react"; import "./CustomSelect.css"; import arrow_down from "../../assets/icons/arrow_down.svg"; -import { getUsers, PaginationRequest, User } from "@api/integration"; + + +type Items = { + id: string; + title: string; + subTitle: string; +} type CustomSelectProps = { - selectedItem: string | null; + items: Items[] | []; + selectedItemId: string | null; setSelectedItem: (value: string | null) => void; - type?: string; + handleScroll: () => void; }; export const CustomSelect: FC = ({ - selectedItem, + items, + selectedItemId, setSelectedItem, - type, + handleScroll, }) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); - const [opened, setOpened] = useState(false); - const [currentValue, setCurrentValue] = useState(selectedItem); - const [users, setUsers] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [page, setPage] = useState(1); - const [hasMoreItems, setHasMoreItems] = useState(true); - const SIZE = 25; + const ref = useRef(null); - const selectWidth = ref.current ? ref.current.offsetWidth : undefined; - const [savedValue, setSavedValue] = useState(null); - const [userName, setUserName] = useState(""); - - const onSelectItem = useCallback( - (event: SelectChangeEvent) => { - const newValue = event.target.value.toString(); - const selectedUser = users.find((user) => user.amoUserID == Number(newValue)); - setUserName(selectedUser.name) - if (selectedUser) { - //для сохранения ID выбранного пользователя в стейт или конфиг... - setSavedValue(selectedUser.id); - } - setCurrentValue(newValue); - setSelectedItem(newValue); - }, - [setSelectedItem, setCurrentValue, setSavedValue, users], - ); + const [opened, setOpened] = useState(false); const toggleOpened = useCallback(() => { setOpened((isOpened) => !isOpened); }, []); - const handleScroll = (e: React.UIEvent) => { + const onScroll = useCallback((e: React.UIEvent) => { const scrollHeight = e.currentTarget.scrollHeight; const scrollTop = e.currentTarget.scrollTop; const clientHeight = e.currentTarget.clientHeight; const scrolledToBottom = scrollTop / (scrollHeight - clientHeight) > 0.9; - if (scrolledToBottom && !isLoading && hasMoreItems) { - setPage((prevPage) => prevPage + 1); + if (scrolledToBottom) { + handleScroll(); } - }; + }, []); - useEffect(() => { - if (type === "typeUsers" && hasMoreItems) { - setIsLoading(true); - const pagination: PaginationRequest = { - page: page, - size: SIZE, - }; - getUsers(pagination).then(([response]) => { - if (response && response.items !== null) { - setUsers((prevItems) => [...prevItems, ...response.items]); - if (response.items.length < SIZE) { - setHasMoreItems(false); - } - } - setIsLoading(false); - }); - } - }, [page, type, hasMoreItems]); + const currentItem = useMemo(() => ( + items.find(item => item.id === selectedItemId) || null + ), [selectedItemId, items]) const menuItems = useMemo(() => { - if (type === "typeUsers" && users && users.length !== 0) { - return users.map((user) => ( + if (items.length !== 0) { + return items.map((item) => ( = ({ padding: isMobile ? "5px 0 5px 20px" : "10px 0 10px 20px", }} > - {user.name} + {item.title} = ({ color: isMobile ? "#9A9AAF" : "#4D4D4D", }} > - {user.email} - - - {user.role} + {item.subTitle} @@ -154,7 +116,7 @@ export const CustomSelect: FC = ({ нет данных ); - }, [users, type]); + }, [items]); return ( @@ -166,7 +128,7 @@ export const CustomSelect: FC = ({ height: "56px", padding: "5px", color: - currentValue === null + currentItem === null ? theme.palette.grey2.main : theme.palette.brightPurple.main, border: `2px solid ${theme.palette.common.white}`, @@ -176,13 +138,13 @@ export const CustomSelect: FC = ({ alignItems: "center", cursor: "pointer", }} - onClick={() => ref.current?.click()} + onClick={() => {if (ref.current !== null) ref.current?.click()}} > = ({ flexGrow: 1, }} > - {userName || "Выберите ответственного за сделку"} + {currentItem?.title || "Выберите ответственного за сделку"} = ({ MenuProps={{ disablePortal: true, PaperProps: { - onScroll: handleScroll, + onScroll: onScroll, style: { zIndex: 2, maxHeight: "300px", overflow: "auto", overflowX: "auto", - maxWidth: selectWidth, }, }, }} sx={{}} - onChange={onSelectItem} + onChange={({ target }: SelectChangeEvent) => setSelectedItem(target.value)} onClick={toggleOpened} > {menuItems} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal.tsx index c8f5073c..0cb1baf4 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal.tsx @@ -1,4 +1,4 @@ -import React, { FC, useEffect, useMemo, useState } from "react"; +import React, { FC, useCallback, useEffect, useMemo, useState } from "react"; import { Dialog, IconButton, @@ -24,15 +24,11 @@ import { AmoModalTitle } from "./AmoModalTitle/AmoModalTitle"; import { AmoSettingsBlock } from "./SettingsBlock/AmoSettingsBlock"; import { AmoAccountInfo } from "./AmoAccountInfo/AmoAccountInfo"; import { AccountResponse, IntegrationRules, Pipeline, Step, User, getAccount, getIntegrationRules, getPipelines, getSteps, getTags, getUsers, setIntegrationRules, updateIntegrationRules } from "@api/integration"; +import { useAmoIntegration } from "./useAmoIntegration"; +import { QuestionKeys, TagKeys } from "./types"; -export type TitleKeys = "Company" | "Lead" | "Customer"; -export type TagQuestionObject = { - backendId: string; - title: string; -}; -export type TQuestionEntity = Record; type IntegrationsModalProps = { isModalOpen: boolean; handleCloseModal: () => void; @@ -40,143 +36,85 @@ type IntegrationsModalProps = { quizID: number | undefined; }; -export type TagKeys = "Contact" | "Company" | "Lead" | "Customer"; -export type TTags = Record; - export const AmoCRMModal: FC = ({ isModalOpen, handleCloseModal, companyName, quizID, }) => { + //Если нет контекста квиза, то и делать на этой страничке нечего + if (quizID === undefined) { + redirect("/list"); + return null; + } + const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isTablet = useMediaQuery(theme.breakpoints.down(1000)); const { questions } = useQuestions(); + const minifiedQuestions = useMemo(() => questions + .filter((q) => + q.type !== "result" + && q.type !== null + ) + .map(({ backendId, title }) => ({ + id: backendId.toString() as string, + title + })), [questions]) + const [step, setStep] = useState(0); const [isSettingsBlock, setIsSettingsBlock] = useState(false); - const [isRemoveAccount, setIsRemoveAccount] = useState(false); + const [isTryRemoveAccount, setIsTryRemoveAccount] = useState(false); - const [firstRules, setFirstRules] = useState(false); - const [accountInfo, setAccountInfo] = useState(null); + const { + isloadingPage, + firstRules, + accountInfo, + arrayOfPipelines, + arrayOfPipelinesSteps, + arrayOfUsers, + arrayOfTags, + selectedPipeline, + setSelectedPipeline, + selectedPipelineStep, + setSelectedPipelineStep, + selectedDealUser, + setSelectedDealPerformer, + questionEntityBackend, + selectedTags, + setSelectedTags, + selectedQuestions, + setSelectedQuestions, + setPageOfPipelines, + setPageOfPipelinesSteps, + setPageOfUsers, + setPageOfTags, + } = useAmoIntegration({ + quizID, + isModalOpen, + isTryRemoveAccount, + }) - const [arrayOfPipelines, setArrayOfPipelines] = useState([]); - const [arrayOfPipelinesSteps, setArrayOfPipelinesSteps] = useState([]); - const [arrayOfUsers, setArrayOfUsers] = useState([]); - const [arrayOfTags, setArrayOfTags] = useState([]); + const handleAddTagQuestion = useCallback((scope: QuestionKeys | TagKeys, id: string, type: "question" | "tag") => { + if (!scope || !id) return; - const [selectedPipeline, setSelectedPipeline] = useState(null); - const [selectedPipelineStep, setSelectedPipelineStep] = useState(null); - const [selectedDealPerformer, setSelectedDealPerformer] = useState(null); - - const [questionEntityBackend, setQuestionEntityBackend] = useState({}); - const [questionEntity, setQuestionEntity] = useState({ - Lead: [], - Company: [], - Customer: [], - }); - const [tags, setTags] = useState({ - Lead: [], - Contact: [], - Company: [], - Customer: [], - }); - - useEffect(() => { - if (isModalOpen && quizID !== undefined && !isRemoveAccount) { - const fetchAccount = async () => { - const [account, error] = await getAccount(); - - if (error) { - if (!error.includes("Not Found")) enqueueSnackbar(error) - setAccountInfo(null); - } - if (account) { - setAccountInfo(account); - } - }; - const fetchRules = async () => { - const [settingsResponse, error] = await getIntegrationRules(quizID.toString()); - - if (error) { - if (error === "first") setFirstRules(true); - if (!error.includes("Not Found") && !error.includes("first")) enqueueSnackbar(error); - } - if (settingsResponse) { - if (settingsResponse.PipelineID) setSelectedPipeline(settingsResponse.PipelineID) - if (settingsResponse.StepID) setSelectedPipelineStep(settingsResponse.StepID) - if (settingsResponse.PerformerID) setSelectedDealPerformer(settingsResponse.PerformerID) - if (Boolean(settingsResponse.FieldsRule) && - Object.keys(settingsResponse.FieldsRule).length > 0) { - const newRules = { ...questionEntity } - setQuestionEntityBackend(settingsResponse.FieldsRule) - for (let key in settingsResponse.FieldsRule) { - if (settingsResponse.FieldsRule[key] !== null && Array.isArray(settingsResponse.FieldsRule[key])) { - const gottenList = Object.keys(settingsResponse.FieldsRule[key][0].QuestionID) - newRules[key] = gottenList - } - } - setQuestionEntity(newRules) - } - if (Boolean(settingsResponse.TagsToAdd) && - Object.keys(settingsResponse.TagsToAdd).length > 0) { - const newRules = { ...tags } - for (let key in settingsResponse.TagsToAdd) { - const gottenList = settingsResponse.TagsToAdd[key] - if (gottenList !== null && Array.isArray(gottenList)) { - newRules[key] = gottenList - } - } - setTags(newRules) - } - setFirstRules(false); - } - - }; - - getTags({ - page: 1, - size: 9999, - }).then(([response]) => { - if (response && response.items !== null) { - setArrayOfTags(response.items); - } - }); - getUsers({ - page: 1, - size: 9999, - }).then(([response]) => { - if (response && response.items !== null) { - setArrayOfUsers(response.items); - } - }); - getPipelines({ - page: 1, - size: 9999, - }).then(([response]) => { - if (response && response.items !== null) { - setArrayOfPipelines(response.items); - } - }) - - fetchAccount(); - fetchRules(); + if (type === "tag") { + setSelectedTags((prevState) => ({ + ...prevState, + [scope]: [...prevState[scope as TagKeys], id], + })); } - }, [isModalOpen, isRemoveAccount]); - useEffect(() => { - if (selectedPipeline !== null) - getSteps({ - page: 1, - size: 9999, - pipelineId: selectedPipeline, - }).then(([response]) => { - if (response && response.items !== null) { - setArrayOfPipelinesSteps(response.items); - } - }); - }, [selectedPipeline]) + + if (type === "question") { + setSelectedQuestions((prevState) => ({ + ...prevState, + [scope]: [...prevState[scope as QuestionKeys], id], + })); + } + }, [setSelectedQuestions, setSelectedTags]); + const handleNextStep = () => { setStep((prevState) => prevState + 1); @@ -189,18 +127,18 @@ export const AmoCRMModal: FC = ({ console.log({ PipelineID: Number(selectedPipeline), StepID: Number(selectedPipelineStep), - PerformerID: Number(selectedDealPerformer), + PerformerID: Number(selectedDealUser), FieldsRule: questionEntity, TagsToAdd: tags }) - if (quizID === undefined) return - if (selectedPipeline === null) return enqueueSnackbar("Выберите воронку") - if (selectedPipeline === null) return enqueueSnackbar("Выберите этап воронки") + if (quizID === undefined) return + if (selectedPipeline === null) return enqueueSnackbar("Выберите воронку") + if (selectedPipeline === null) return enqueueSnackbar("Выберите этап воронки") const body = { PipelineID: Number(selectedPipeline), StepID: Number(selectedPipelineStep), - PerformerID: Number(selectedDealPerformer), + PerformerID: Number(selectedDealUser), FieldsRule: questionEntityBackend, TagsToAdd: tags } @@ -220,14 +158,14 @@ export const AmoCRMModal: FC = ({ console.log(body) - if (firstRules) { - setIntegrationRules(quizID.toString(), body) - } else { - updateIntegrationRules(quizID.toString(), body) - } + if (firstRules) { + setIntegrationRules(quizID.toString(), body) + } else { + updateIntegrationRules(quizID.toString(), body) + } - handleCloseModal(); - setStep(1); + handleCloseModal(); + setStep(1); }; const steps = useMemo( () => [ @@ -252,8 +190,8 @@ export const AmoCRMModal: FC = ({ @@ -266,7 +204,7 @@ export const AmoCRMModal: FC = ({ = ({ ), @@ -291,11 +229,12 @@ export const AmoCRMModal: FC = ({ isSettingsAvailable: true, component: ( {}} + handleAddTag={handleAddTagQuestion} handlePrevStep={handlePrevStep} handleNextStep={handleNextStep} - setIdTags={setTags} - arrayOfTags={arrayOfTags} /> ), }, @@ -304,30 +243,25 @@ export const AmoCRMModal: FC = ({ isSettingsAvailable: true, component: ( ), }, ], [ - accountInfo, - questionEntity, - selectedPipeline, - selectedPipelineStep, - selectedDealPerformer, - tags, + arrayOfPipelines, + arrayOfPipelinesSteps, + arrayOfUsers, + arrayOfTags, ], ); const stepTitles = steps.map((step) => step.title); - //Если нет контекста квиза, то и делать на этой страничке нечего - if (quizID === undefined) return redirect("/list") - return ( = ({ isSettingsBlock={isSettingsBlock} setIsSettingsBlock={setIsSettingsBlock} setStep={setStep} - startRemoveAccount={() => setIsRemoveAccount(true)} + startRemoveAccount={() => setIsTryRemoveAccount(true)} /> - {isRemoveAccount && ( + {isTryRemoveAccount && ( setIsRemoveAccount(false)} + stopThisPage={() => setIsTryRemoveAccount(false)} /> )} {isSettingsBlock && ( @@ -403,15 +337,15 @@ export const AmoCRMModal: FC = ({ stepTitles={stepTitles} setIsSettingsBlock={setIsSettingsBlock} setStep={setStep} - selectedDealPerformer={arrayOfUsers.find(p => p.amoUserID == selectedDealPerformer)?.name || null} - selectedFunnel={arrayOfPipelines.find(p => selectedPipeline)?.Name || null} - selectedStage={arrayOfPipelinesSteps.find(p => selectedPipelineStep)?.Name || null} - questionEntity={questionEntity} - tags={tags} + selectedDealUser={selectedDealUser} + selectedFunnel={selectedPipeline} + selectedStage={selectedPipelineStep} + selectedQuestions={selectedQuestions} + selectedTags={selectedTags} /> )} - {!isSettingsBlock && !isRemoveAccount && ( + {!isSettingsBlock && !isTryRemoveAccount && ( {steps[step].component} )} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/AmoQuestions.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/AmoQuestions.tsx index 55807220..5b407512 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/AmoQuestions.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/AmoQuestions.tsx @@ -1,79 +1,40 @@ -import { useTheme } from "@mui/material"; import { - Dispatch, FC, - SetStateAction, - useCallback, - useMemo, useState, } from "react"; import { ItemsSelectionView } from "./ItemsSelectionView/ItemsSelectionView"; import { ItemDetailsView } from "./ItemDetailsView/ItemDetailsView"; -import { TagQuestionObject, TitleKeys, TQuestionEntity } from "../AmoCRMModal"; -import Box from "@mui/material/Box"; -import type { AllTypesQuestion } from "@model/questionTypes/shared" -import { getQuestionById } from "@/stores/questions/actions"; -import { useQuestionsStore } from "@/stores/questions/store"; +import { Box } from "@mui/material"; +import { QuestionKeys, SelectedQuestions, TagKeys } from "../types"; +type Items = { + id: string; + title: string; + subTitle?: string; +}; type Props = { + questionsItems: Items[] | []; + selectedQuestions: SelectedQuestions; + handleAddQuestion: (scope: QuestionKeys | TagKeys, id: string, type: "question" | "tag") => void; handlePrevStep: () => void; handleNextStep: () => void; - questionEntity: TQuestionEntity; - setQuestionEntity: Dispatch>; - questions: AllTypesQuestion[]; }; export const AmoQuestions: FC = ({ + questionsItems, + selectedQuestions, + handleAddQuestion, handlePrevStep, handleNextStep, - questionEntity, - setQuestionEntity, - questions, }) => { - const theme = useTheme(); const [isSelection, setIsSelection] = useState(false); - const [activeItem, setActiveItem] = useState(null); - const [selectedValue, setSelectedValue] = useState(null); + const [activeScope, setActiveScope] = useState(null); + const [selectedQuestion, setSelectedQuestion] = useState(null); - const handleAdd = useCallback(() => { - if (!activeItem || !selectedValue) return; - - setQuestionEntity((prevState) => ({ - ...prevState, - [activeItem]: [...prevState[activeItem as TitleKeys], Number(selectedValue)], - })); - }, [activeItem, setQuestionEntity, selectedValue]); - - const items: TagQuestionObject[] = useMemo( - () => Object.values(questions) - .filter(({ type }) => - type !== "result" - && type !== null) - .map(({ backendId, title }) => ({ - backendId: backendId, - title - })), - [], - ); - const translatedQuestionEntity = useMemo(() => { - const translated = { - - } as TQuestionEntity; - - for (let key in questionEntity) { - if (questionEntity[key] !== "Contact") { - console.log(translated) - console.log(translated[key]) - console.log(questionEntity) - translated[key] = questionEntity[key].map((id) => - questions.find((q) => q.backendId === Number(id))?.title || id) - } - } - - return translated - }, - [questionEntity], - ) + const handleAdd = () => { + if (activeScope === null || selectedQuestion === null) return + handleAddQuestion(activeScope, selectedQuestion, "question") + } return ( = ({ flexGrow: 1, }} > - {isSelection ? ( + {isSelection && activeScope !== null ? ( + // Здесь выбираем элемент в табличку { - setActiveItem(null); + setActiveScope(null); setIsSelection(false); }} onLargeBtnClick={() => { handleAdd(); - setActiveItem(null); + setActiveScope(null); setIsSelection(false); }} /> ) : ( + // Табличка )} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemDetailsView/ItemDetailsView.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemDetailsView/ItemDetailsView.tsx index 64c14426..8c6eb719 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemDetailsView/ItemDetailsView.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemDetailsView/ItemDetailsView.tsx @@ -2,7 +2,7 @@ import { Box, useTheme } from "@mui/material"; import { Item } from "../Item/Item"; import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock"; import { FC } from "react"; -import { TQuestionEntity } from "../../AmoCRMModal"; +import { QuestionKeys, SelectedQuestions } from "../../types"; type TitleKeys = "Contact" | "Company" | "Lead" | "Customer"; @@ -10,16 +10,16 @@ type ItemDetailsViewProps = { setIsSelection: (value: boolean) => void; handleSmallBtn: () => void; handleLargeBtn: () => void; - questionEntity: TQuestionEntity; - setActiveItem: (value: string | null) => void; + selectedQuestions: SelectedQuestions; + setActiveScope: (value: QuestionKeys | null) => void; }; export const ItemDetailsView: FC = ({ handleSmallBtn, handleLargeBtn, - questionEntity, - setActiveItem, + selectedQuestions, setIsSelection, + setActiveScope, }) => { const theme = useTheme(); @@ -48,16 +48,16 @@ export const ItemDetailsView: FC = ({ justifyContent: "start", }} > - {questionEntity && - Object.keys(questionEntity).map((item) => ( + {selectedQuestions && + Object.keys(selectedQuestions).map((item) => ( { setIsSelection(true); - setActiveItem(item); + setActiveScope(item as QuestionKeys); }} - data={questionEntity} + data={selectedQuestions} /> ))} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemsSelectionView/ItemsSelectionView.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemsSelectionView/ItemsSelectionView.tsx index f79ff169..893d3a0a 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemsSelectionView/ItemsSelectionView.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoQuestions/ItemsSelectionView/ItemsSelectionView.tsx @@ -2,30 +2,28 @@ import { Box } from "@mui/material"; import { CustomRadioGroup } from "../../../../../components/CustomRadioGroup/CustomRadioGroup"; import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock"; import { FC } from "react"; -import { AllTypesQuestion } from "@/model/questionTypes/shared"; -import type { TagQuestionObject } from "@/pages/IntegrationsPage/IntegrationsModal/AmoCRMModal" -import { Tag } from "@api/integration"; +type Items = { + id: string; + title: string; + subTitle?: string; +}; type ItemsSelectionViewProps = { - type?: string; - items?: TagQuestionObject[]; - selectedValue: string | null; - setSelectedValue: (value: string | null) => void; + items: Items[] | []; + selectedItemId?: string | null; + setSelectedItem: (value: string | null) => void; + handleScroll?: () => void; onLargeBtnClick: () => void; onSmallBtnClick: () => void; - setTags: (setValueFunc: (value: Tag[]) => Tag[]) => void; - parentTags: Tag[] }; export const ItemsSelectionView: FC = ({ items, - selectedValue, - setSelectedValue, + selectedItemId, + setSelectedItem, + handleScroll, onLargeBtnClick, onSmallBtnClick, - type, - parentTags, - setTags }) => { return ( = ({ }} > void; + tagsItems: Items[] | []; + selectedTags: SelectedTags; + handleAddTag: (scope: QuestionKeys | TagKeys, id: string, type: "question" | "tag") => void; + handleScroll: () => void; handlePrevStep: () => void; - tagsNames: TTags; - setIdTags: Dispatch>; - arrayOfTags: TTags[] + handleNextStep: () => void; }; export const AmoTags: FC = ({ - handleNextStep, + tagsItems, + selectedTags, + handleAddTag, + handleScroll, handlePrevStep, - tagsNames, - setIdTags, - arrayOfTags, + handleNextStep, }) => { - const theme = useTheme(); const [isSelection, setIsSelection] = useState(false); - const [activeTag, setActiveItem] = useState(null); - const [selectedValue, setSelectedValue] = useState(null); - const [tags, setTags] = useState([]); - const [tagsNamesList, setTagsNamesList] = useState>({ - Lead: [], - Contact: [], - Company: [], - Customer: [], - }); - const handleAdd = useCallback(() => { - if (!activeTag || !selectedValue) return; + const [activeScope, setActiveScope] = useState(null); + const [selectedTag, setSelectedTag] = useState(null); - setIdTags((prevState) => ({ - ...prevState, - [activeTag]: [...prevState[activeTag as TagKeys], Number(selectedValue)], - })); - setTagsNamesList((prevState) => ({ - ...prevState, - [activeTag]: [...prevState[activeTag as TagKeys], arrayOfTags.find((tag) => tag.AmoID == selectedValue).Name], - })); - }, [activeTag, setIdTags, selectedValue]); + const handleAdd = () => { + if (activeScope === null || selectedTag === null) return + handleAddTag(activeScope, selectedTag, "tag") + } return ( = ({ flexGrow: 1, }} > - {isSelection ? ( + {isSelection && activeScope !== null ? ( + // Здесь выбираем элемент в табличку { - setActiveItem(null); + setActiveScope(null); setIsSelection(false); }} onLargeBtnClick={() => { handleAdd(); - setActiveItem(null); + setActiveScope(null); setIsSelection(false); }} /> ) : ( + // Табличка )} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/AmoTags/TagsDetailsView/TagsDetailsView.tsx b/src/pages/IntegrationsPage/IntegrationsModal/AmoTags/TagsDetailsView/TagsDetailsView.tsx index b350b265..ffac6c9d 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/AmoTags/TagsDetailsView/TagsDetailsView.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/AmoTags/TagsDetailsView/TagsDetailsView.tsx @@ -1,25 +1,23 @@ import { Box, Typography, useTheme } from "@mui/material"; import { StepButtonsBlock } from "../../StepButtonsBlock/StepButtonsBlock"; import { FC } from "react"; -import { TagKeys, TitleKeys, TTags } from "../../AmoCRMModal"; import { Item } from "../../AmoQuestions/Item/Item"; +import { SelectedTags, TagKeys } from "../../types"; type TagsDetailsViewProps = { setIsSelection: (value: boolean) => void; handlePrevStep: () => void; handleNextStep: () => void; - tagsNames: TTags; - setActiveItem: (value: string | null) => void; - tagsNamesList: Record + setActiveScope: (value: TagKeys | null) => void; + selectedTags: SelectedTags; }; export const TagsDetailsView: FC = ({ + setActiveScope, + selectedTags, + setIsSelection, handlePrevStep, handleNextStep, - tagsNames, - setActiveItem, - setIsSelection, - tagsNamesList, }) => { const theme = useTheme(); @@ -70,17 +68,16 @@ export const TagsDetailsView: FC = ({ justifyContent: "start", }} > - {tagsNames && - Object.keys(tagsNames).map((item) => ( + {selectedTags && + Object.keys(selectedTags).map((item) => ( { setIsSelection(true); - setActiveItem(item); + setActiveScope(item as TagKeys); }} - data={tagsNames} + data={selectedTags} /> ))} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/DealPerformers/DealPerformers.tsx b/src/pages/IntegrationsPage/IntegrationsModal/DealPerformers/DealPerformers.tsx index 37fcdce4..061506c5 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/DealPerformers/DealPerformers.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/DealPerformers/DealPerformers.tsx @@ -6,14 +6,14 @@ import { CustomSelect } from "../../../../components/CustomSelect/CustomSelect"; type Props = { handlePrevStep: () => void; handleNextStep: () => void; - selectedDealPerformer: number | null; - setSelectedDealPerformer: (value: number | null) => void; + selectedDealUser: string | null; + setSelectedDealPerformer: (value: string | null) => void; }; export const DealPerformers: FC = ({ handlePrevStep, handleNextStep, - selectedDealPerformer, + selectedDealUser, setSelectedDealPerformer, }) => { const theme = useTheme(); @@ -32,9 +32,10 @@ export const DealPerformers: FC = ({ > void; handleNextStep: () => void; - selectedStepsPerformer: number | null; - setSelectedStepsPerformer: (value: number | null) => void; - selectedStep: number | null; - setSelectedStep: (value: number | null) => void; - pipelineId: number | null; + selectedStepsPerformer: string | null; + setSelectedStepsPerformer: (value: string | null) => void; + selectedStep: string | null; + setSelectedStep: (value: string | null) => void; + pipelineId: string | null; }; export const PipelineSteps: FC = ({ @@ -39,9 +39,10 @@ export const PipelineSteps: FC = ({ > = ({ }} > void; handleNextStep: () => void; - selectedPipelinePerformer: number | null; - setSelectedPipelinePerformer: (value: number | null) => void; - selectedPipeline: number | null; - setSelectedPipeline: (value: number | null) => void; + selectedPipelinePerformer: string | null; + setSelectedPipelineUser: (value: string | null) => void; + selectedPipeline: string | null; + setSelectedPipeline: (value: string | null) => void; }; @@ -18,7 +18,7 @@ export const Pipelines: FC = ({ handlePrevStep, handleNextStep, selectedPipelinePerformer, - setSelectedPipelinePerformer, + setSelectedPipelineUser, selectedPipeline, setSelectedPipeline, }) => { @@ -37,9 +37,10 @@ export const Pipelines: FC = ({ > = ({ }} > void; setIsSettingsBlock: (value: boolean) => void; - selectedFunnel: number | null; - selectedStage: number | null; - selectedDealPerformer: string | null; - questionEntity: TQuestionEntity; - tags: TTags; + selectedFunnel: string | null; + selectedStage: string | null; + selectedDealUser: string | null; + selectedQuestions: SelectedQuestions; + selectedTags: SelectedTags; }; export const AmoSettingsBlock: FC = ({ @@ -20,10 +20,10 @@ export const AmoSettingsBlock: FC = ({ setStep, setIsSettingsBlock, selectedFunnel, - selectedDealPerformer, + selectedDealUser, selectedStage, - questionEntity, - tags, + selectedQuestions, + selectedTags, }) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); @@ -57,11 +57,11 @@ export const AmoSettingsBlock: FC = ({ title={title} setIsSettingsBlock={setIsSettingsBlock} setStep={setStep} - selectedDealPerformer={selectedDealPerformer} + selectedDealUser={selectedDealUser} selectedFunnel={selectedFunnel} selectedStage={selectedStage} - questionEntity={questionEntity} - tags={tags} + selectedQuestions={selectedQuestions} + selectedTags={selectedTags} /> ))} diff --git a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx index 8c18246e..eae751e7 100644 --- a/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx +++ b/src/pages/IntegrationsPage/IntegrationsModal/SettingsBlock/SettingItem/SettingItem.tsx @@ -4,7 +4,7 @@ import { Typography, useMediaQuery, useTheme } from "@mui/material"; import { SettingItemHeader } from "./SettingItemHeader/SettingItemHeader"; import { ResponsiblePerson } from "./ResponsiblePerson/ResponsiblePerson"; import { SelectedParameter } from "./SelectedParameter/SelectedParameter"; -import { TQuestionEntity, TTags } from "../../AmoCRMModal"; +import { SelectedQuestions, SelectedTags } from "../../types"; type SettingItemProps = { step: number; @@ -14,10 +14,10 @@ type SettingItemProps = { selectedFunnelPerformer: string | null; selectedFunnel: string | null; selectedStagePerformer: string | null; - selectedDealPerformer: string | null; + selectedDealUser: string | null; selectedStage: string | null; - questionEntity: TQuestionEntity; - tags: TTags; + selectedQuestions: SelectedQuestions; + selectedTags: SelectedTags; }; export const SettingItem: FC = ({ @@ -28,10 +28,10 @@ export const SettingItem: FC = ({ selectedFunnelPerformer, selectedFunnel, selectedStagePerformer, - selectedDealPerformer, + selectedDealUser, selectedStage, - questionEntity, - tags, + selectedQuestions, + selectedTags, }) => { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(600)); @@ -43,7 +43,7 @@ export const SettingItem: FC = ({ if (step === 1) { return ( <> - + ); @@ -51,7 +51,7 @@ export const SettingItem: FC = ({ if (step === 2) { return ( <> - + ); @@ -59,12 +59,12 @@ export const SettingItem: FC = ({ if (step === 3) { return ( <> - + ); } if (step === 4) { - const isFilled = Object.values(questionEntity).some( + const isFilled = Object.values(selectedQuestions).some( (array) => array.length > 0, ); const status = isFilled ? "Заполнено" : "Не заполнено"; @@ -96,7 +96,7 @@ export const SettingItem: FC = ({ ); } if (step === 5) { - const isFilled = Object.values(tags).some((array) => array.length > 0); + const isFilled = Object.values(selectedTags).some((array) => array.length > 0); const status = isFilled ? "Заполнено" : "Не заполнено"; return ( @@ -131,10 +131,10 @@ export const SettingItem: FC = ({ selectedFunnelPerformer, selectedFunnel, selectedStagePerformer, - selectedDealPerformer, + selectedDealUser, selectedStage, - questionEntity, - tags, + selectedQuestions, + selectedTags, ]); return ( diff --git a/src/pages/IntegrationsPage/IntegrationsModal/types.ts b/src/pages/IntegrationsPage/IntegrationsModal/types.ts new file mode 100644 index 00000000..dea47062 --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/types.ts @@ -0,0 +1,11 @@ +export type TagKeys = "Contact" | "Company" | "Lead" | "Customer"; +export type SelectedTags = Record; + +export type QuestionKeys = "Company" | "Lead" | "Customer"; +export type SelectedQuestions = Record; + +export type minifiedData = { + id: string; + title: string; + subTitle?: string; +}; \ No newline at end of file diff --git a/src/pages/IntegrationsPage/IntegrationsModal/useAmoIntegration.ts b/src/pages/IntegrationsPage/IntegrationsModal/useAmoIntegration.ts new file mode 100644 index 00000000..99c1ccde --- /dev/null +++ b/src/pages/IntegrationsPage/IntegrationsModal/useAmoIntegration.ts @@ -0,0 +1,250 @@ +import { FC, 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, +} from "@/api/integration"; + +const SIZE = 25; + +interface Props { + isModalOpen: boolean; + isTryRemoveAccount: boolean; + quizID: number; +} + +export const useAmoIntegration = ({ + isModalOpen, + isTryRemoveAccount, + quizID, +}: Props) => { + const [isloadingPage, setIsLoadingPage] = useState(true); + const [firstRules, setFirstRules] = useState(false); + const [accountInfo, setAccountInfo] = useState(null); + + const [arrayOfPipelines, setArrayOfPipelines] = useState([]); + const [arrayOfPipelinesSteps, setArrayOfPipelinesSteps] = useState([]); + const [arrayOfUsers, setArrayOfUsers] = useState([]); + const [arrayOfTags, setArrayOfTags] = useState([]); + + const [selectedPipeline, setSelectedPipeline] = useState(null); + const [selectedPipelineStep, setSelectedPipelineStep] = useState(null); + const [selectedDealUser, setSelectedDealPerformer] = useState(null); + + const [questionEntityBackend, setQuestionEntityBackend] = useState, number> | {}>({}); + const [selectedTags, setSelectedTags] = useState({ + Lead: [], + Contact: [], + Company: [], + Customer: [], + }); + const [selectedQuestions, setSelectedQuestions] = useState({ + Lead: [], + Company: [], + Customer: [], + }); + + const [pageOfPipelines, setPageOfPipelines] = useState(1); + const [pageOfPipelinesSteps, setPageOfPipelinesSteps] = useState(1); + const [pageOfUsers, setPageOfUsers] = useState(1); + const [pageOfTags, setPageOfTags] = useState(1); + + useEffect(() => { + if (isModalOpen && !isTryRemoveAccount) { + 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) setSelectedPipeline(settingsResponse.PipelineID.toString()) + if (settingsResponse.StepID) setSelectedPipelineStep(settingsResponse.StepID.toString()) + if (settingsResponse.PerformerID) setSelectedDealPerformer(settingsResponse.PerformerID.toString()) + + if (Boolean(settingsResponse.FieldsRule) && + Object.keys(settingsResponse?.FieldsRule).length > 0) { + const gottenQuestions = { ...selectedQuestions } + setQuestionEntityBackend(settingsResponse.FieldsRule) + + for (let key in settingsResponse.FieldsRule) { + if (settingsResponse.FieldsRule[key as QuestionKeys] !== null && Array.isArray(settingsResponse.FieldsRule[key as QuestionKeys])) { + + const gottenList = settingsResponse.FieldsRule[key as QuestionKeys] + + if (gottenList !== null) + gottenQuestions[key as QuestionKeys] = Object.keys(gottenList[0].QuestionID) + } + } + 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(); + } else { + //Вот по-хорошему компонент должен размонтироваться и стереть всё. Но это будет сделано позже + setArrayOfPipelines([]); + setArrayOfPipelinesSteps([]); + setArrayOfUsers([]); + setArrayOfTags([]); + setSelectedPipeline(null); + setSelectedPipelineStep(null); + setSelectedDealPerformer(null); + setQuestionEntityBackend({}); + setSelectedTags({ + Lead: [], + Contact: [], + Company: [], + Customer: [], + }); + setSelectedQuestions({ + Lead: [], + Company: [], + Customer: [], + }); + setPageOfPipelines(1); + setPageOfPipelinesSteps(1); + setPageOfUsers(1); + setPageOfTags(1); + } + }, [isModalOpen, isTryRemoveAccount]); + + useEffect(() => { + getPipelines({ + page: pageOfPipelines, + size: SIZE, + }).then(([response]) => { + if (response && response.items !== null) { + const minifiedPipelines: minifiedData[] = [] + + response.items.forEach((step) => { + minifiedPipelines.push({ + id: step.AmoID.toString(), + title: step.Name + }) + }) + setArrayOfPipelines((prevItems) => [...prevItems, ...minifiedPipelines]); + } + }) + }, [pageOfPipelines]) + useEffect(() => { + 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((prevItems) => [...prevItems, ...minifiedSteps]); + } + }); + }, [selectedPipeline, pageOfPipelinesSteps]) + useEffect(() => { + getUsers({ + page: pageOfUsers, + size: SIZE, + }).then(([response]) => { + if (response && response.items !== null) { + const minifiedUsers: minifiedData[] = [] + + response.items.forEach((step) => { + minifiedUsers.push({ + id: step.amoID.toString(), + title: step.name + }) + }) + setArrayOfUsers((prevItems) => [...prevItems, ...minifiedUsers]); + } + }); + }, [pageOfUsers]) + useEffect(() => { + getTags({ + page: pageOfTags, + size: SIZE, + }).then(([response]) => { + if (response && response.items !== null) { + const minifiedTags: minifiedData[] = [] + + response.items.forEach((step) => { + minifiedTags.push({ + id: step.AmoID.toString(), + title: step.Name + }) + }) + setArrayOfTags((prevItems) => [...prevItems, ...minifiedTags]); + } + }); + }, [pageOfTags]) + + return ({ + isloadingPage, + firstRules, + accountInfo, + arrayOfPipelines, + arrayOfPipelinesSteps, + arrayOfUsers, + arrayOfTags, + selectedPipeline, + setSelectedPipeline, + selectedPipelineStep, + setSelectedPipelineStep, + selectedDealUser, + setSelectedDealPerformer, + questionEntityBackend, + selectedTags, + setSelectedTags, + selectedQuestions, + setSelectedQuestions, + setPageOfPipelines, + setPageOfPipelinesSteps, + setPageOfUsers, + setPageOfTags, + }) +} \ No newline at end of file From 9e4c94d09eddd35bf3143e1b7eec279406ca837e Mon Sep 17 00:00:00 2001 From: Nastya Date: Sun, 16 Jun 2024 13:48:49 +0300 Subject: [PATCH 04/11] =?UTF-8?q?amo=20fix=20types,=20=D0=B2=D1=8B=D0=B2?= =?UTF-8?q?=D0=BE=D0=B4=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8=D0=B9?= =?UTF-8?q?=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20id,=20=D1=83=D0=B4?= =?UTF-8?q?=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=D1=8B=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B2=D0=BE=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=81=D0=BE=D0=B2=20=D0=B8=20=D1=82=D0=B5=D0=B3=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/integration.ts | 22 +-- .../CustomRadioGroup/CustomRadioGroup.tsx | 36 ++-- src/components/CustomSelect/CustomSelect.tsx | 16 +- .../IntegrationsModal/AmoCRMModal.tsx | 155 ++++++++++++------ .../AmoQuestions/AmoQuestions.tsx | 19 ++- .../Item/AnswerItem/AnswerItem.tsx | 66 +++++--- .../AmoQuestions/Item/Item.tsx | 27 ++- .../ItemDetailsView/ItemDetailsView.tsx | 12 +- .../ItemsSelectionView/ItemsSelectionView.tsx | 8 +- .../AmoRemoveAccount/AmoDeleteTagQuestion.tsx | 49 ++++++ .../IntegrationsModal/AmoTags/AmoTags.tsx | 24 ++- .../TagsDetailsView/TagsDetailsView.tsx | 10 +- .../DealPerformers/DealPerformers.tsx | 11 +- .../PipelineSteps/PipelineSteps.tsx | 37 +++-- .../IntegrationsModal/Pipelines/Pipelines.tsx | 35 ++-- .../SettingsBlock/SettingItem/SettingItem.tsx | 6 +- .../IntegrationsModal/types.ts | 13 +- .../IntegrationsModal/useAmoIntegration.ts | 42 +++-- 18 files changed, 394 insertions(+), 194 deletions(-) create mode 100644 src/pages/IntegrationsPage/IntegrationsModal/AmoRemoveAccount/AmoDeleteTagQuestion.tsx diff --git a/src/api/integration.ts b/src/api/integration.ts index a23fd89a..09d5b2f5 100644 --- a/src/api/integration.ts +++ b/src/api/integration.ts @@ -1,3 +1,4 @@ +import { QuestionKeys } from "@/pages/IntegrationsPage/IntegrationsModal/types"; import { makeRequest } from "@api/makeRequest"; import { parseAxiosError } from "@utils/parse-error"; @@ -225,29 +226,13 @@ export const getPipelines = async ({ }; //получение настроек интеграции -type QuestionID = Record +export type QuestionID = Record export type IntegrationRules = { PipelineID: number; StepID: number; PerformerID?: number; - FieldsRule: { - Lead: [ - { - QuestionID: QuestionID; - } - ] | null, - Company: [ - { - QuestionID: QuestionID; - } - ] | null, - Customer: [ - { - QuestionID: QuestionID; - } - ] | null, - }; + FieldsRule: FieldsRule; TagsToAdd: { Lead: number[] | null; Contact: number[] | null; @@ -255,6 +240,7 @@ export type IntegrationRules = { Customer: number[] | null; } }; +export type FieldsRule = Record, null | [{QuestionID: QuestionID;}]> export const getIntegrationRules = async ( quizID: string, diff --git a/src/components/CustomRadioGroup/CustomRadioGroup.tsx b/src/components/CustomRadioGroup/CustomRadioGroup.tsx index f7ba0a8c..3de16dd3 100644 --- a/src/components/CustomRadioGroup/CustomRadioGroup.tsx +++ b/src/components/CustomRadioGroup/CustomRadioGroup.tsx @@ -10,18 +10,15 @@ import { RadioGroup, Radio, } from "@mui/material"; +import { MinifiedData, TagKeys } from "@/pages/IntegrationsPage/IntegrationsModal/types"; -type Items = { - id: string; - title: string; - subTitle?: string; -} type CustomRadioGroupProps = { - items: Items[] | []; + items: MinifiedData[] | []; selectedItemId?: string | null; setSelectedItem: (value: string | null) => void; handleScroll: () => void; + activeScope?: TagKeys; }; export const CustomRadioGroup: FC = ({ @@ -29,6 +26,7 @@ export const CustomRadioGroup: FC = ({ selectedItemId = "", setSelectedItem, handleScroll, + activeScope, }) => { const theme = useTheme(); @@ -39,6 +37,14 @@ export const CustomRadioGroup: FC = ({ return null; }, [selectedItemId, items]) + const filteredItems = useMemo(() => { + let newArray = items + if (activeScope !== undefined) newArray =newArray.filter(item => { + return item.entity === activeScope + }) + return newArray + }, items) + const onScroll = React.useCallback((e: React.UIEvent) => { const scrollHeight = e.currentTarget.scrollHeight; const scrollTop = e.currentTarget.scrollTop; @@ -52,9 +58,9 @@ export const CustomRadioGroup: FC = ({ const formControlLabels = useMemo(() => { - if (items.length !== 0) { - return items.map( item => - + = ({ borderRadius: "12px", margin: 0, backgroundColor: - currentItem?.id === item.id + currentItem?.id === item.id ? theme.palette.background.default : theme.palette.common.white, + "&.MuiFormControlLabel-root > .MuiTypography-root": { + width: "200px", + overflow: "hidden", + textOverflow: "ellipsis" + } + }} value={item.id} control={ @@ -100,7 +112,7 @@ export const CustomRadioGroup: FC = ({ Нет элементов ); - }, [items]); + }, [filteredItems, selectedItemId]); return ( = ({ ) => setSelectedItem(target.value)} onScroll={onScroll} > diff --git a/src/components/CustomSelect/CustomSelect.tsx b/src/components/CustomSelect/CustomSelect.tsx index 929ed823..700287c4 100644 --- a/src/components/CustomSelect/CustomSelect.tsx +++ b/src/components/CustomSelect/CustomSelect.tsx @@ -13,22 +13,15 @@ import { } from "@mui/material"; import "./CustomSelect.css"; import arrow_down from "../../assets/icons/arrow_down.svg"; - - -type Items = { - id: string; - title: string; - subTitle: string; -} +import { MinifiedData } from "@/pages/IntegrationsPage/IntegrationsModal/types"; type CustomSelectProps = { - items: Items[] | []; + items: MinifiedData[] | []; selectedItemId: string | null; setSelectedItem: (value: string | null) => void; handleScroll: () => void; }; - export const CustomSelect: FC = ({ items, selectedItemId, @@ -39,7 +32,6 @@ export const CustomSelect: FC = ({ const isMobile = useMediaQuery(theme.breakpoints.down(600)); const ref = useRef(null); - const [opened, setOpened] = useState(false); const toggleOpened = useCallback(() => { @@ -116,7 +108,7 @@ export const CustomSelect: FC = ({ нет данных ); - }, [items]); + }, [items, selectedItemId]); return ( @@ -171,7 +163,7 @@ export const CustomSelect: FC = ({ { let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion)); - newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = ( - event.target as HTMLSelectElement - ).value; + newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = (event.target as HTMLSelectElement).value; setParentQuestion(newParentQuestion); }} sx={{ @@ -247,7 +216,10 @@ const SelectorType = ({ sx={{ color: theme.palette.grey2.main }} value={Boolean(Number(totalIndex))} control={ - } icon={} /> + } + icon={} + /> } label={condition} /> @@ -257,12 +229,7 @@ const SelectorType = ({ ); }; -const DateInputsType = ({ - parentQuestion, - targetQuestion, - ruleIndex, - setParentQuestion, -}: Props) => { +const DateInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => { const theme = useTheme(); const upLg = useMediaQuery(theme.breakpoints.up("md")); @@ -277,8 +244,7 @@ const DateInputsType = ({ let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion)); newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = time; - if (newParentQuestion.content.dateRange) - parentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] = time; + if (newParentQuestion.content.dateRange) parentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] = time; setParentQuestion(newParentQuestion); }, [firstDate, secondDate, firstTime, secondTime]); @@ -302,9 +268,7 @@ const DateInputsType = ({ pb: "5px", }} > - - Новое условие - + Новое условие { @@ -324,12 +288,8 @@ const DateInputsType = ({ pb: "10px", }} > - - Дан ответ - - - (Укажите один или несколько вариантов) - + Дан ответ + (Укажите один или несколько вариантов) {parentQuestion.content.dateRange && ( - - (Начало периода) - + (Начало периода) )} { const date = dateString?.toDate().toLocaleDateString("ru-RU", { @@ -356,9 +312,7 @@ const DateInputsType = ({ day: "2-digit", }); let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion)); - newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [ - date, - ]; + newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [date]; setParentQuestion(newParentQuestion); }} slots={{ @@ -392,9 +346,7 @@ const DateInputsType = ({ /> {parentQuestion.content.time && ( {parentQuestion.content.dateRange && ( - - (Конец периода) - + (Конец периода) )} {}} slots={{ openPickerIcon: () => , @@ -464,9 +412,7 @@ const DateInputsType = ({ /> {parentQuestion.content.time && ( ); }; -const NumberInputsType = ({ - parentQuestion, - targetQuestion, - ruleIndex, - setParentQuestion, -}: Props) => { +const NumberInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => { const theme = useTheme(); const quizId = Number(useParams().quizId); @@ -519,9 +460,7 @@ const NumberInputsType = ({ pb: "5px", }} > - - Новое условие - + Новое условие { @@ -541,35 +480,23 @@ const NumberInputsType = ({ pb: "10px", }} > - - Дан ответ - - - (Укажите один или несколько вариантов) - + Дан ответ + (Укажите один или несколько вариантов) ) => { - const newParentQuestion = JSON.parse( - JSON.stringify(parentQuestion), - ); - const previousValue = - newParentQuestion.content.rule.main[ruleIndex].rules[0] - .answers[0]; - newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = - (parentQuestion as QuizQuestionNumber).content.chooseRange - ? previousValue - ? `${target.value}—${previousValue.split("—")[1] || 0}` - : `${target.value}—0` - : target.value; + const newParentQuestion = JSON.parse(JSON.stringify(parentQuestion)); + const previousValue = newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]; + newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = (parentQuestion as QuizQuestionNumber) + .content.chooseRange + ? previousValue + ? `${target.value}—${previousValue.split("—")[1] || 0}` + : `${target.value}—0` + : target.value; setParentQuestion(newParentQuestion); }} /> @@ -577,21 +504,11 @@ const NumberInputsType = ({ ) => { - const newParentQuestion = JSON.parse( - JSON.stringify(parentQuestion), - ); - const previousValue = - newParentQuestion.content.rule.main[ruleIndex].rules[0] - .answers[0]; - newParentQuestion.content.rule.main[ - ruleIndex - ].rules[0].answers[0] = previousValue + const newParentQuestion = JSON.parse(JSON.stringify(parentQuestion)); + const previousValue = newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]; + newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = previousValue ? `${previousValue.split("—")[0] || 0}—${target.value}` : `0—${target.value}`; setParentQuestion(newParentQuestion); @@ -602,12 +519,7 @@ const NumberInputsType = ({ ); }; -const TextInputsType = ({ - parentQuestion, - targetQuestion, - ruleIndex, - setParentQuestion, -}: Props) => { +const TextInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => { const theme = useTheme(); const quizId = Number(useParams().quizId); @@ -630,9 +542,7 @@ const TextInputsType = ({ pb: "5px", }} > - - Новое условие - + Новое условие { @@ -652,12 +562,9 @@ const TextInputsType = ({ pb: "10px", }} > - - Дан ответ - + Дан ответ - (Укажите текст, при совпадении с которым пользователь попадёт на этот - вопрос) + (Укажите текст, при совпадении с которым пользователь попадёт на этот вопрос) ) => { let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion)); - newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [ - (event.target as HTMLInputElement).value, - ]; + newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [(event.target as HTMLInputElement).value]; setParentQuestion(newParentQuestion); }} /> ); }; -const FileInputsType = ({ - parentQuestion, - targetQuestion, - ruleIndex, - setParentQuestion, -}: Props) => { +const FileInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => { const theme = useTheme(); const quizId = Number(useParams().quizId); @@ -705,9 +605,7 @@ const FileInputsType = ({ pb: "5px", }} > - - Новое условие - + Новое условие { @@ -737,15 +635,12 @@ const FileInputsType = ({ sx={{ margin: 0, }} - checked={ - parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] - } + checked={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]} onChange={(event: React.FormEvent) => { - let newParentQuestion = JSON.parse( - JSON.stringify(parentQuestion), - ); - newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = - [(event.target as HTMLInputElement).checked]; + let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion)); + newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [ + (event.target as HTMLInputElement).checked, + ]; setParentQuestion(newParentQuestion); }} /> @@ -755,12 +650,7 @@ const FileInputsType = ({ ); }; -const RatingInputsType = ({ - parentQuestion, - targetQuestion, - ruleIndex, - setParentQuestion, -}: Props) => { +const RatingInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => { const theme = useTheme(); const quizId = Number(useParams().quizId); @@ -783,9 +673,7 @@ const RatingInputsType = ({ pb: "5px", }} > - - Новое условие - + Новое условие { @@ -817,16 +705,9 @@ const RatingInputsType = ({ value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]} onChange={(event: React.FormEvent) => { let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion)); - let valueNumber = Number( - (event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, ""), - ); - valueNumber = - valueNumber > parentQuestion.content.steps - ? parentQuestion.content.steps - : valueNumber; - newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [ - valueNumber, - ]; + let valueNumber = Number((event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, "")); + valueNumber = valueNumber > parentQuestion.content.steps ? parentQuestion.content.steps : valueNumber; + newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [valueNumber]; setParentQuestion(newParentQuestion); }} /> diff --git a/src/pages/Questions/BranchingQuestionsModal/index.tsx b/src/pages/Questions/BranchingQuestionsModal/index.tsx index b59af7ed..6e5cbbb6 100644 --- a/src/pages/Questions/BranchingQuestionsModal/index.tsx +++ b/src/pages/Questions/BranchingQuestionsModal/index.tsx @@ -10,12 +10,9 @@ import { useTheme, } from "@mui/material"; import { useQuestionsStore } from "@root/questions/store"; -import { AnyTypedQuizQuestion } from "@model/questionTypes/shared"; +import { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; import { useUiTools } from "@root/uiTools/store"; -import { - setModalQuestionTargetContentId, - setOpenedModalQuestions, -} from "@root/uiTools/actions"; +import { setModalQuestionTargetContentId, setOpenedModalQuestions } from "@root/uiTools/actions"; import React, { useEffect, useState } from "react"; import RadioCheck from "@ui_kit/RadioCheck"; import RadioIcon from "@ui_kit/RadioIcon"; @@ -26,20 +23,16 @@ export const BranchingQuestionsModal = () => { const isMobile = useMediaQuery(theme.breakpoints.down(650)); const trashQuestions = useQuestionsStore().questions; - const questions = trashQuestions.filter( - (question) => question.type !== "result", - ); + const questions = trashQuestions.filter((question) => question.type !== "result"); - const openedModalQuestions = useUiTools( - (state) => state.openedModalQuestions, - ); + const openedModalQuestions = useUiTools((state) => state.openedModalQuestions); const handleClose = () => { setOpenedModalQuestions(false); }; const typedQuestions: AnyTypedQuizQuestion[] = questions.filter( - (question) => question.type && question.type !== "result", + (question) => question.type && question.type !== "result" ) as AnyTypedQuizQuestion[]; if (typedQuestions.length === 0) return <>; @@ -64,7 +57,10 @@ export const BranchingQuestionsModal = () => { }; return ( - + { boxShadow: 24, }} > - + { control={ } - icon={ - question.content.rule.parentId ? ( - - ) : ( - - ) - } + icon={question.content.rule.parentId ? : } /> } label={question.title || "нет заголовка"} @@ -125,10 +113,7 @@ export const BranchingQuestionsModal = () => { padding: "8px 12px", margin: 0, width: "100%", - backgroundColor: - index % 2 === 0 - ? theme.palette.common.white - : "rgba(242, 243, 247, 0.5)", + backgroundColor: index % 2 === 0 ? theme.palette.common.white : "rgba(242, 243, 247, 0.5)", color: theme.palette.grey3.main, }} /> diff --git a/src/pages/Questions/ButtonsOptions.tsx b/src/pages/Questions/ButtonsOptions.tsx index 424231ba..785b0a9c 100644 --- a/src/pages/Questions/ButtonsOptions.tsx +++ b/src/pages/Questions/ButtonsOptions.tsx @@ -1,19 +1,7 @@ import { DeleteIcon } from "@icons/questionsPage/deleteIcon"; import type { SxProps } from "@mui/material"; -import { - Box, - Button, - IconButton, - Modal, - Typography, - useMediaQuery, - useTheme, -} from "@mui/material"; -import { - copyQuestion, - deleteQuestion, - deleteQuestionWithTimeout, -} from "@root/questions/actions"; +import { Box, Button, IconButton, Modal, Typography, useMediaQuery, useTheme } from "@mui/material"; +import { copyQuestion, deleteQuestion, deleteQuestionWithTimeout } from "@root/questions/actions"; import { useQuestionsStore } from "@root/questions/store"; import { useCurrentQuiz } from "@root/quizes/hooks"; import { updateDesireToOpenABranchingModal } from "@root/uiTools/actions"; @@ -24,8 +12,7 @@ import { CopyIcon } from "../../assets/icons/questionsPage/CopyIcon"; import Branching from "../../assets/icons/questionsPage/branching"; import SettingIcon from "../../assets/icons/questionsPage/settingIcon"; import { QuestionType } from "@model/question/question"; - -import type { AnyTypedQuizQuestion } from "@model/questionTypes/shared"; +import type { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; interface Props { switchState: string; @@ -52,9 +39,7 @@ const ButtonsOptions = memo(function ({ const isWrappMiniButtonSetting = useMediaQuery(theme.breakpoints.down(920)); const quiz = useCurrentQuiz(); const [openDelete, setOpenDelete] = useState(false); - const isQuestionFirst = useQuestionsStore( - (state) => state.questions[0]?.id === questionId, - ); + const isQuestionFirst = useQuestionsStore((state) => state.questions[0]?.id === questionId); if (!quiz) return null; @@ -70,24 +55,12 @@ const ButtonsOptions = memo(function ({ myFunc?: any; }[] = [ { - icon: ( - - ), + icon: , title: "Настройки", value: "setting", }, { - icon: ( - - ), + icon: , title: "Ветвление", value: "branching", myFunc: (question: AnyTypedQuizQuestion) => { @@ -119,9 +92,7 @@ const ButtonsOptions = memo(function ({ {buttonSetting.map(({ icon, title, value, myFunc }) => ( {value === "branching" ? ( - ["page", "text", "date", "number"].includes( - questionType, - ) ? null : ( + ["page", "text", "date", "number"].includes(questionType) ? null : ( { @@ -129,14 +100,8 @@ const ButtonsOptions = memo(function ({ }} sx={{ display: quiz.config.type === "form" ? "none" : "flex", - backgroundColor: - switchState === value - ? theme.palette.brightPurple.main - : "transparent", - color: - switchState === value - ? "#ffffff" - : theme.palette.grey3.main, + backgroundColor: switchState === value ? theme.palette.brightPurple.main : "transparent", + color: switchState === value ? "#ffffff" : theme.palette.grey3.main, minWidth: isWrappMiniButtonSetting ? "30px" : "64px", height: "30px", "&:hover": { @@ -157,14 +122,8 @@ const ButtonsOptions = memo(function ({ myFunc(); }} sx={{ - backgroundColor: - switchState === value - ? theme.palette.brightPurple.main - : "transparent", - color: - switchState === value - ? "#ffffff" - : theme.palette.grey3.main, + backgroundColor: switchState === value ? theme.palette.brightPurple.main : "transparent", + color: switchState === value ? "#ffffff" : theme.palette.grey3.main, minWidth: isWrappMiniButtonSetting ? "30px" : "64px", height: "30px", "&:hover": { @@ -203,9 +162,7 @@ const ButtonsOptions = memo(function ({ if (questionHasParent) { setOpenDelete(true); } else { - deleteQuestionWithTimeout(questionId, () => - DeleteFunction(questionId), - ); + deleteQuestionWithTimeout(questionId, () => DeleteFunction(questionId)); } }} data-cy="delete-question" @@ -213,7 +170,10 @@ const ButtonsOptions = memo(function ({ )} - setOpenDelete(false)}> + setOpenDelete(false)} + > (function ({ background: "#FFFFFF", }} > - - Вы удаляете вопрос, участвующий в ветвлении. Все его потомки - потеряют данные ветвления. Вы уверены, что хотите удалить вопрос? + + Вы удаляете вопрос, участвующий в ветвлении. Все его потомки потеряют данные ветвления. Вы уверены, что + хотите удалить вопрос? (function ({ variant="contained" sx={{ minWidth: "150px" }} onClick={() => { - deleteQuestionWithTimeout(questionId, () => - DeleteFunction(questionId), - ); + deleteQuestionWithTimeout(questionId, () => DeleteFunction(questionId)); }} > Подтвердить diff --git a/src/pages/Questions/DataOptions/DataOptions.tsx b/src/pages/Questions/DataOptions/DataOptions.tsx index 472921bb..3bd586ff 100644 --- a/src/pages/Questions/DataOptions/DataOptions.tsx +++ b/src/pages/Questions/DataOptions/DataOptions.tsx @@ -1,16 +1,10 @@ -import { - Box, - Tooltip, - Typography, - useMediaQuery, - useTheme, -} from "@mui/material"; +import { Box, Tooltip, Typography, useMediaQuery, useTheme } from "@mui/material"; import { useState } from "react"; import InfoIcon from "../../../assets/icons/InfoIcon"; import ButtonsOptions from "../ButtonsOptions"; import SwitchData from "./switchData"; -import { QuizQuestionDate } from "@model/questionTypes/date"; import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo"; +import { QuizQuestionDate } from "@frontend/squzanswerer"; interface Props { question: QuizQuestionDate; @@ -18,11 +12,7 @@ interface Props { setOpenBranchingPage: (a: boolean) => void; } -export default function DataOptions({ - question, - openBranchingPage, - setOpenBranchingPage, -}: Props) { +export default function DataOptions({ question, openBranchingPage, setOpenBranchingPage }: Props) { const [switchState, setSwitchState] = useState("setting"); const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(790)); @@ -61,7 +51,10 @@ export default function DataOptions({ {isMobile ? ( ) : ( - + @@ -75,10 +68,13 @@ export default function DataOptions({ questionId={question.id} questionContentId={question.content.id} questionType={question.type} - questionHasParent={question.content.rule.parentId.length !== 0} + questionHasParent={question.content.rule.parentId?.length !== 0} setOpenBranchingPage={setOpenBranchingPage} /> - + ); } diff --git a/src/pages/Questions/DataOptions/settingData.tsx b/src/pages/Questions/DataOptions/settingData.tsx index 9b9f290a..cc58720b 100644 --- a/src/pages/Questions/DataOptions/settingData.tsx +++ b/src/pages/Questions/DataOptions/settingData.tsx @@ -1,7 +1,7 @@ import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; import { updateQuestion } from "@root/questions/actions"; import CustomCheckbox from "@ui_kit/CustomCheckbox"; -import type { QuizQuestionDate } from "../../../model/questionTypes/date"; +import type { QuizQuestionDate } from "@frontend/squzanswerer"; type SettingsDataProps = { questionId: string; @@ -12,7 +12,6 @@ type SettingsDataProps = { export default function SettingsData({ questionId, isRequired, isDateRange, isTime }: SettingsDataProps) { const theme = useTheme(); - const isWrappColumn = useMediaQuery(theme.breakpoints.down(980)); const isMobile = useMediaQuery(theme.breakpoints.down(790)); const isTablet = useMediaQuery(theme.breakpoints.down(900)); const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990)); diff --git a/src/pages/Questions/DataOptions/switchData.tsx b/src/pages/Questions/DataOptions/switchData.tsx index 18c2997b..76eb1806 100644 --- a/src/pages/Questions/DataOptions/switchData.tsx +++ b/src/pages/Questions/DataOptions/switchData.tsx @@ -1,4 +1,4 @@ -import { QuizQuestionDate } from "@model/questionTypes/date"; +import { QuizQuestionDate } from "@frontend/squzanswerer"; import HelpQuestions from "../helpQuestions"; import SettingData from "./settingData"; diff --git a/src/pages/Questions/DraggableList/DraggableListItem.tsx b/src/pages/Questions/DraggableList/DraggableListItem.tsx index 2fe4be63..efc57524 100644 --- a/src/pages/Questions/DraggableList/DraggableListItem.tsx +++ b/src/pages/Questions/DraggableList/DraggableListItem.tsx @@ -1,7 +1,4 @@ -import { - AnyTypedQuizQuestion, - UntypedQuizQuestion, -} from "@model/questionTypes/shared"; +import { UntypedQuizQuestion } from "@model/questionTypes/shared"; import { Box, ListItem, Typography, useTheme } from "@mui/material"; import { cancelQuestionDeletion } from "@root/questions/actions"; import { updateEditSomeQuestion } from "@root/uiTools/actions"; @@ -9,6 +6,7 @@ import { useUiTools } from "@root/uiTools/store"; import { memo, useEffect } from "react"; import { Draggable } from "react-beautiful-dnd"; import QuestionsPageCard from "./QuestionPageCard"; +import { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; type Props = { question: AnyTypedQuizQuestion | UntypedQuizQuestion; @@ -48,7 +46,10 @@ const DraggableListItem = memo(function ({ }, [editSomeQuestion]); return ( - + {(provided) => ( 0 - : false - } + questionHasParent={"content" in question ? question.content.rule.parentId.length > 0 : false} /> {question.expanded && ( diff --git a/src/pages/Questions/DropDown/DropDown.tsx b/src/pages/Questions/DropDown/DropDown.tsx index 5c8109d6..b1fe9e49 100644 --- a/src/pages/Questions/DropDown/DropDown.tsx +++ b/src/pages/Questions/DropDown/DropDown.tsx @@ -6,7 +6,7 @@ import { AnswerDraggableList } from "../AnswerDraggableList"; import ButtonsOptions from "../ButtonsOptions"; import SwitchDropDown from "./switchDropDown"; -import type { QuizQuestionSelect } from "../../../model/questionTypes/select"; +import type { QuizQuestionSelect } from "@frontend/squzanswerer"; import AnswerItem from "../AnswerDraggableList/AnswerItem"; interface Props { @@ -15,11 +15,7 @@ interface Props { setOpenBranchingPage: (a: boolean) => void; } -export default function DropDown({ - question, - openBranchingPage, - setOpenBranchingPage, -}: Props) { +export default function DropDown({ question, openBranchingPage, setOpenBranchingPage }: Props) { const onClickAddAnAnswer = useAddAnswer(); const [switchState, setSwitchState] = useState("setting"); const theme = useTheme(); @@ -108,10 +104,13 @@ export default function DropDown({ questionId={question.id} questionContentId={question.content.id} questionType={question.type} - questionHasParent={question.content.rule.parentId.length !== 0} + questionHasParent={question.content.rule.parentId?.length !== 0} setOpenBranchingPage={setOpenBranchingPage} /> - + ); } diff --git a/src/pages/Questions/DropDown/settingDropDown.tsx b/src/pages/Questions/DropDown/settingDropDown.tsx index fc7bde72..5549ff86 100644 --- a/src/pages/Questions/DropDown/settingDropDown.tsx +++ b/src/pages/Questions/DropDown/settingDropDown.tsx @@ -3,7 +3,7 @@ import { updateQuestion } from "@root/questions/actions"; import CustomCheckbox from "@ui_kit/CustomCheckbox"; import CustomTextField from "@ui_kit/CustomTextField"; import { memo } from "react"; -import type { QuizQuestionSelect } from "../../../model/questionTypes/select"; +import type { QuizQuestionSelect } from "@frontend/squzanswerer"; type SettingDropDownProps = { questionId: string; @@ -11,11 +11,7 @@ type SettingDropDownProps = { isRequired: boolean; }; -const SettingDropDown = memo(function ({ - questionId, - questionContentDefault, - isRequired, -}) { +const SettingDropDown = memo(function ({ questionId, questionContentDefault, isRequired }) { const theme = useTheme(); const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990)); const isMobile = useMediaQuery(theme.breakpoints.down(790)); diff --git a/src/pages/Questions/DropDown/switchDropDown.tsx b/src/pages/Questions/DropDown/switchDropDown.tsx index 1f7724f1..7c748f59 100644 --- a/src/pages/Questions/DropDown/switchDropDown.tsx +++ b/src/pages/Questions/DropDown/switchDropDown.tsx @@ -1,4 +1,4 @@ -import { QuizQuestionSelect } from "@model/questionTypes/select"; +import { QuizQuestionSelect } from "@frontend/squzanswerer"; import HelpQuestions from "../helpQuestions"; import SettingDropDown from "./settingDropDown"; @@ -7,10 +7,7 @@ interface Props { question: QuizQuestionSelect; } -export default function SwitchDropDown({ - switchState = "setting", - question, -}: Props) { +export default function SwitchDropDown({ switchState = "setting", question }: Props) { switch (switchState) { case "setting": return ( diff --git a/src/pages/Questions/Emoji/Emoji.tsx b/src/pages/Questions/Emoji/Emoji.tsx index f1b9da71..3942e675 100644 --- a/src/pages/Questions/Emoji/Emoji.tsx +++ b/src/pages/Questions/Emoji/Emoji.tsx @@ -1,16 +1,9 @@ -import { - Box, - Link, - Popover, - Typography, - useMediaQuery, - useTheme, -} from "@mui/material"; +import { Box, Link, Popover, Typography, useMediaQuery, useTheme } from "@mui/material"; import { updateQuestion } from "@root/questions/actions"; import { EmojiPicker } from "@ui_kit/EmojiPicker"; import { useState } from "react"; import { EnterIcon } from "../../../assets/icons/questionsPage/enterIcon"; -import type { QuizQuestionEmoji } from "../../../model/questionTypes/emoji"; +import type { QuizQuestionEmoji } from "@frontend/squzanswerer"; import { useAddAnswer } from "../../../utils/hooks/useAddAnswer"; import { AnswerDraggableList } from "../AnswerDraggableList"; import ButtonsOptions from "../ButtonsOptions"; @@ -23,17 +16,11 @@ interface Props { setOpenBranchingPage: (a: boolean) => void; } -export default function Emoji({ - question, - openBranchingPage, - setOpenBranchingPage, -}: Props) { +export default function Emoji({ question, openBranchingPage, setOpenBranchingPage }: Props) { const [switchState, setSwitchState] = useState("setting"); const onClickAddAnAnswer = useAddAnswer(); const [open, setOpen] = useState(false); - const [anchorElement, setAnchorElement] = useState( - null, - ); + const [anchorElement, setAnchorElement] = useState(null); const [selectedVariant, setSelectedVariant] = useState(null); const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(790)); @@ -79,9 +66,7 @@ export default function Emoji({ updateQuestion(question.id, (question) => { if (question.type !== "emoji") return; - const variant = question.content.variants.find( - (v) => v.id === selectedVariant, - ); + const variant = question.content.variants.find((v) => v.id === selectedVariant); if (!variant) return; variant.extendedText = native; @@ -134,10 +119,13 @@ export default function Emoji({ questionId={question.id} questionContentId={question.content.id} questionType={question.type} - questionHasParent={question.content.rule.parentId.length !== 0} + questionHasParent={question.content.rule.parentId?.length !== 0} setOpenBranchingPage={setOpenBranchingPage} /> - + ); } diff --git a/src/pages/Questions/Emoji/settingEmoji.tsx b/src/pages/Questions/Emoji/settingEmoji.tsx index a885c267..12116556 100644 --- a/src/pages/Questions/Emoji/settingEmoji.tsx +++ b/src/pages/Questions/Emoji/settingEmoji.tsx @@ -1,9 +1,8 @@ +import type { QuizQuestionEmoji, QuizQuestionVariant } from "@frontend/squzanswerer"; import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; import { updateQuestion } from "@root/questions/actions"; import CustomCheckbox from "@ui_kit/CustomCheckbox"; -import type { QuizQuestionEmoji } from "../../../model/questionTypes/emoji"; import { memo } from "react"; -import type { QuizQuestionVariant } from "@model/questionTypes/variant"; type SettingEmojiProps = { questionId: string; diff --git a/src/pages/Questions/Emoji/switchEmoji.tsx b/src/pages/Questions/Emoji/switchEmoji.tsx index e7cfbb96..c9ae5fc8 100644 --- a/src/pages/Questions/Emoji/switchEmoji.tsx +++ b/src/pages/Questions/Emoji/switchEmoji.tsx @@ -1,4 +1,4 @@ -import { QuizQuestionEmoji } from "@model/questionTypes/emoji"; +import { QuizQuestionEmoji } from "@frontend/squzanswerer"; import HelpQuestions from "../helpQuestions"; import SettingEmoji from "./settingEmoji"; diff --git a/src/pages/Questions/Form/FormDraggableList/ChooseAnswerModal.tsx b/src/pages/Questions/Form/FormDraggableList/ChooseAnswerModal.tsx index 3dff994a..6e9008ac 100644 --- a/src/pages/Questions/Form/FormDraggableList/ChooseAnswerModal.tsx +++ b/src/pages/Questions/Form/FormDraggableList/ChooseAnswerModal.tsx @@ -15,11 +15,9 @@ import { import { changeQuestionType } from "@root/questions/actions"; import type { RefObject } from "react"; import { useState } from "react"; -import type { - AnyTypedQuizQuestion, - UntypedQuizQuestion, -} from "../../../../model/questionTypes/shared"; +import type { UntypedQuizQuestion } from "../../../../model/questionTypes/shared"; import { BUTTON_TYPE_QUESTIONS } from "../../TypeQuestions"; +import { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; type ChooseAnswerModalProps = { open: boolean; @@ -29,13 +27,7 @@ type ChooseAnswerModalProps = { questionType: QuestionType | null; }; -export const ChooseAnswerModal = ({ - open, - onClose, - anchorRef, - question, - questionType, -}: ChooseAnswerModalProps) => { +export const ChooseAnswerModal = ({ open, onClose, anchorRef, question, questionType }: ChooseAnswerModalProps) => { const [openModal, setOpenModal] = useState(false); const [selectedValue, setSelectedValue] = useState("text"); const theme = useTheme(); @@ -69,10 +61,7 @@ export const ChooseAnswerModal = ({ {icon} {title} @@ -85,7 +74,10 @@ export const ChooseAnswerModal = ({ )} - setOpenModal(false)}> + setOpenModal(false)} + > - - Все настройки, кроме заголовка вопроса будут сброшены - + Все настройки, кроме заголовка вопроса будут сброшены { +export const FormItem = ({ question, questionIndex, provided }: FormItemProps) => { const theme = useTheme(); return ( @@ -85,24 +79,25 @@ export const FormItem = ({ ); }; -export const FormDraggableListItem = memo( - ({ question, questionIndex }: FormDraggableListItemProps) => ( - - {(provided) => ( - - - - )} - - ), -); +export const FormDraggableListItem = memo(({ question, questionIndex }: FormDraggableListItemProps) => ( + + {(provided) => ( + + + + )} + +)); FormDraggableListItem.displayName = "FormDraggableListItem"; diff --git a/src/pages/Questions/Form/FormDraggableList/QuestionPageCard.tsx b/src/pages/Questions/Form/FormDraggableList/QuestionPageCard.tsx index 6e34c8cb..13477448 100644 --- a/src/pages/Questions/Form/FormDraggableList/QuestionPageCard.tsx +++ b/src/pages/Questions/Form/FormDraggableList/QuestionPageCard.tsx @@ -1,7 +1,10 @@ +import { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; +import { ArrowDownIcon } from "@icons/questionsPage/ArrowDownIcon"; +import { CopyIcon } from "@icons/questionsPage/CopyIcon"; import { PointsIcon } from "@icons/questionsPage/PointsIcon"; import Answer from "@icons/questionsPage/answer"; -import AnswerGroup from "@icons/questionsPage/answerGroup"; import Date from "@icons/questionsPage/date"; +import { DeleteIcon } from "@icons/questionsPage/deleteIcon"; import Download from "@icons/questionsPage/download"; import DropDown from "@icons/questionsPage/drop_down"; import Emoji from "@icons/questionsPage/emoji"; @@ -11,19 +14,19 @@ import OptionsPict from "@icons/questionsPage/options_pict"; import Page from "@icons/questionsPage/page"; import RatingIcon from "@icons/questionsPage/rating"; import Slider from "@icons/questionsPage/slider"; +import { QuestionType } from "@model/question/question"; +import ExpandLessIcon from "@mui/icons-material/ExpandLess"; import { Box, - Checkbox, FormControl, - FormControlLabel, IconButton, InputAdornment, - Paper, TextField as MuiTextField, + Paper, + TextFieldProps, Typography, useMediaQuery, useTheme, - TextFieldProps, } from "@mui/material"; import { copyQuestion, @@ -33,28 +36,12 @@ import { updateQuestion, updateUntypedQuestion, } from "@root/questions/actions"; -import CustomTextField from "@ui_kit/CustomTextField"; import { FC, useRef, useState } from "react"; import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd"; -import { useDebouncedCallback } from "use-debounce"; -import type { - AnyTypedQuizQuestion, - UntypedQuizQuestion, -} from "../../../../model/questionTypes/shared"; +import type { UntypedQuizQuestion } from "../../../../model/questionTypes/shared"; import SwitchQuestionsPage from "../../SwitchQuestionsPage"; -import { ChooseAnswerModal } from "./ChooseAnswerModal"; import FormTypeQuestions from "../FormTypeQuestions"; -import { QuestionType } from "@model/question/question"; -import { CrossedEyeIcon } from "@icons/CrossedEyeIcon"; -import { ArrowDownIcon } from "@icons/questionsPage/ArrowDownIcon"; -import { CopyIcon } from "@icons/questionsPage/CopyIcon"; -import { DeleteIcon } from "@icons/questionsPage/deleteIcon"; -import { HideIcon } from "@icons/questionsPage/hideIcon"; -import ExpandLessIcon from "@mui/icons-material/ExpandLess"; -import { - NoLuggageOutlined, - SignalCellularNullOutlined, -} from "@mui/icons-material"; +import { ChooseAnswerModal } from "./ChooseAnswerModal"; const TextField = MuiTextField as unknown as FC; @@ -64,11 +51,7 @@ interface Props { draggableProps: DraggableProvidedDragHandleProps | null | undefined; } -export default function QuestionsPageCard({ - question, - questionIndex, - draggableProps, -}: Props) { +export default function QuestionsPageCard({ question, questionIndex, draggableProps }: Props) { const maxLengthTextField = 225; const [open, setOpen] = useState(false); const [isTextFieldtActive, setIsTextFieldtActive] = useState(false); @@ -78,8 +61,7 @@ export default function QuestionsPageCard({ const isMobile = useMediaQuery(theme.breakpoints.down(790)); const setTitle = (title: string) => { - const updateQuestionFn = - question.type === null ? updateUntypedQuestion : updateQuestion; + const updateQuestionFn = question.type === null ? updateUntypedQuestion : updateQuestion; updateQuestionFn(question.id, (question) => { question.title = title; @@ -148,9 +130,7 @@ export default function QuestionsPageCard({ margin: isMobile ? "10px 0" : 0, "& .MuiInputBase-root": { color: "#000000", - backgroundColor: question.expanded - ? theme.palette.background.default - : "transparent", + backgroundColor: question.expanded ? theme.palette.background.default : "transparent", height: "48px", borderRadius: "10px", ".MuiOutlinedInput-notchedOutline": { @@ -186,27 +166,22 @@ export default function QuestionsPageCard({ /> ), - endAdornment: isTextFieldtActive && - question.title.length >= maxLengthTextField - 7 && ( - - - {question.title.length} - - / - - {maxLengthTextField} - - - ), + endAdornment: isTextFieldtActive && question.title.length >= maxLengthTextField - 7 && ( + + {question.title.length} + / + {maxLengthTextField} + + ), }} /> @@ -268,9 +243,7 @@ export default function QuestionsPageCard({ sx={{ padding: "0" }} onClick={() => copyQuestion(question.id, question.quizId)} > - + {questionIndex > 0 && ( { - deleteQuestionWithTimeout(question.id, () => - deleteQuestion(question.id), - ); + deleteQuestionWithTimeout(question.id, () => deleteQuestion(question.id)); }} > - + )} @@ -304,12 +273,8 @@ export default function QuestionsPageCard({ marginLeft: "3px", borderRadius: "50%", fontSize: "16px", - color: question.expanded - ? theme.palette.brightPurple.main - : "#FFF", - background: question.expanded - ? "#EEE4FC" - : theme.palette.brightPurple.main, + color: question.expanded ? theme.palette.brightPurple.main : "#FFF", + background: question.expanded ? "#EEE4FC" : theme.palette.brightPurple.main, }} > {questionIndex + 1} @@ -349,10 +314,18 @@ export default function QuestionsPageCard({ const IconAndrom = (questionType: QuestionType | null) => { switch (questionType) { case "variant": - return ; + return ( + + ); case "images": return ( - + ); case "varimg": return ( @@ -362,26 +335,60 @@ const IconAndrom = (questionType: QuestionType | null) => { /> ); case "emoji": - return ; + return ( + + ); case "text": - return ; + return ( + + ); case "select": return ( - + ); case "date": - return ; + return ( + + ); case "number": - return ; + return ( + + ); case "file": return ( - + ); case "page": - return ; + return ( + + ); case "rating": return ( - + ); default: return null; diff --git a/src/pages/Questions/OptionsAndPicture/OptionsAndPicture.tsx b/src/pages/Questions/OptionsAndPicture/OptionsAndPicture.tsx index 651b4859..3d5516a8 100644 --- a/src/pages/Questions/OptionsAndPicture/OptionsAndPicture.tsx +++ b/src/pages/Questions/OptionsAndPicture/OptionsAndPicture.tsx @@ -1,14 +1,10 @@ import { Box, Link, Typography, useMediaQuery, useTheme } from "@mui/material"; -import { - addQuestionVariant, - clearQuestionImages, - uploadQuestionImage, -} from "@root/questions/actions"; +import { addQuestionVariant, clearQuestionImages, uploadQuestionImage } from "@root/questions/actions"; import { useCurrentQuiz } from "@root/quizes/hooks"; import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal"; import { useEffect, useState } from "react"; import { EnterIcon } from "../../../assets/icons/questionsPage/enterIcon"; -import type { QuizQuestionVarImg } from "../../../model/questionTypes/varimg"; +import type { QuizQuestionVarImg } from "@frontend/squzanswerer"; import { useDisclosure } from "../../../utils/useDisclosure"; import { AnswerDraggableList } from "../AnswerDraggableList"; import ImageEditAnswerItem from "../AnswerDraggableList/ImageEditAnswerItem"; @@ -22,50 +18,31 @@ interface Props { setOpenBranchingPage: (a: boolean) => void; } -export default function OptionsAndPicture({ - question, - setOpenBranchingPage, -}: Props) { +export default function OptionsAndPicture({ question, setOpenBranchingPage }: Props) { const [switchState, setSwitchState] = useState("setting"); const [pictureUploding, setPictureUploading] = useState(false); - const [selectedVariantId, setSelectedVariantId] = useState( - null, - ); + const [selectedVariantId, setSelectedVariantId] = useState(null); const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(790)); const quizQid = useCurrentQuiz()?.qid; - const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = - useDisclosure(); - const { - isCropModalOpen, - openCropModal, - closeCropModal, - imageBlob, - originalImageUrl, - setCropModalImageBlob, - } = useCropModalState(); + const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = useDisclosure(); + const { isCropModalOpen, openCropModal, closeCropModal, imageBlob, originalImageUrl, setCropModalImageBlob } = + useCropModalState(); const handleImageUpload = async (file: File) => { if (!selectedVariantId) return; setPictureUploading(true); - const url = await uploadQuestionImage( - question.id, - quizQid, - file, - (question, url) => { - if (!("variants" in question.content)) return; + const url = await uploadQuestionImage(question.id, quizQid, file, (question, url) => { + if (!("variants" in question.content)) return; - const variant = question.content.variants.find( - (variant) => variant.id === selectedVariantId, - ); - if (!variant) return; + const variant = question.content.variants.find((variant) => variant.id === selectedVariantId); + if (!variant) return; - variant.extendedText = url; - variant.originalImageUrl = url; - }, - ); + variant.extendedText = url; + variant.originalImageUrl = url; + }); closeImageUploadModal(); openCropModal(file, url); @@ -78,9 +55,7 @@ export default function OptionsAndPicture({ uploadQuestionImage(question.id, quizQid, imageBlob, (question, url) => { if (!("variants" in question.content)) return; - const variant = question.content.variants.find( - (variant) => variant.id === selectedVariantId, - ); + const variant = question.content.variants.find((variant) => variant.id === selectedVariantId); if (!variant) return; variant.extendedText = url; @@ -127,8 +102,7 @@ export default function OptionsAndPicture({ onClose={closeCropModal} onSaveImageClick={handleCropModalSaveClick} onDeleteClick={() => { - if (selectedVariantId) - clearQuestionImages(question.id, selectedVariantId); + if (selectedVariantId) clearQuestionImages(question.id, selectedVariantId); }} cropAspectRatio={{ width: 300, height: 300 }} /> @@ -183,12 +157,15 @@ export default function OptionsAndPicture({ SSHC={setSwitchState} questionId={question.id} questionContentId={question.content.id} - questionHasParent={question.content.rule.parentId.length !== 0} + questionHasParent={question.content.rule.parentId?.length !== 0} questionType={question.type} openBranchingPage={false} setOpenBranchingPage={setOpenBranchingPage} /> - + ); } diff --git a/src/pages/Questions/OptionsAndPicture/SettingOptionsAndPict.tsx b/src/pages/Questions/OptionsAndPicture/SettingOptionsAndPict.tsx index 5e0535b5..05ea8e63 100644 --- a/src/pages/Questions/OptionsAndPicture/SettingOptionsAndPict.tsx +++ b/src/pages/Questions/OptionsAndPicture/SettingOptionsAndPict.tsx @@ -1,10 +1,9 @@ +import type { QuizQuestionVarImg, QuizQuestionVariant } from "@frontend/squzanswerer"; import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; import { updateQuestion } from "@root/questions/actions"; import CustomCheckbox from "@ui_kit/CustomCheckbox"; import CustomTextField from "@ui_kit/CustomTextField"; -import type { QuizQuestionVarImg } from "../../../model/questionTypes/varimg"; import { memo } from "react"; -import type { QuizQuestionVariant } from "@model/questionTypes/variant"; type SettingOptionsAndPictProps = { questionId: string; diff --git a/src/pages/Questions/OptionsAndPicture/switchOptionsAndPict.tsx b/src/pages/Questions/OptionsAndPicture/switchOptionsAndPict.tsx index 2243f045..4b2e40e1 100644 --- a/src/pages/Questions/OptionsAndPicture/switchOptionsAndPict.tsx +++ b/src/pages/Questions/OptionsAndPicture/switchOptionsAndPict.tsx @@ -1,4 +1,4 @@ -import { QuizQuestionVarImg } from "@model/questionTypes/varimg"; +import { QuizQuestionVarImg } from "@frontend/squzanswerer"; import UploadImage from "../UploadImage"; import HelpQuestions from "../helpQuestions"; import SettingOptionsAndPict from "./SettingOptionsAndPict"; @@ -28,7 +28,12 @@ export default function SwitchOptionsAndPict({ switchState = "setting", question /> ); case "image": - return ; + return ( + + ); default: return null; } diff --git a/src/pages/Questions/OptionsPicture/OptionsPicture.tsx b/src/pages/Questions/OptionsPicture/OptionsPicture.tsx index 1c148795..cef09aea 100644 --- a/src/pages/Questions/OptionsPicture/OptionsPicture.tsx +++ b/src/pages/Questions/OptionsPicture/OptionsPicture.tsx @@ -1,13 +1,10 @@ import { Box, Link, Typography, useMediaQuery, useTheme } from "@mui/material"; -import { - clearQuestionImages, - uploadQuestionImage, -} from "@root/questions/actions"; +import { clearQuestionImages, uploadQuestionImage } from "@root/questions/actions"; import { useCurrentQuiz } from "@root/quizes/hooks"; import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal"; import { useState } from "react"; import { EnterIcon } from "../../../assets/icons/questionsPage/enterIcon"; -import type { QuizQuestionImages } from "../../../model/questionTypes/images"; +import type { QuizQuestionImages } from "@frontend/squzanswerer"; import { useAddAnswer } from "../../../utils/hooks/useAddAnswer"; import { useDisclosure } from "../../../utils/useDisclosure"; import { AnswerDraggableList } from "../AnswerDraggableList"; @@ -22,52 +19,32 @@ interface Props { setOpenBranchingPage: (a: boolean) => void; } -export default function OptionsPicture({ - question, - openBranchingPage, - setOpenBranchingPage, -}: Props) { +export default function OptionsPicture({ question, openBranchingPage, setOpenBranchingPage }: Props) { const theme = useTheme(); const onClickAddAnAnswer = useAddAnswer(); const quizQid = useCurrentQuiz()?.qid; const [pictureUploding, setPictureUploading] = useState(false); - const [selectedVariantId, setSelectedVariantId] = useState( - null, - ); + const [selectedVariantId, setSelectedVariantId] = useState(null); const [switchState, setSwitchState] = useState("setting"); const isMobile = useMediaQuery(theme.breakpoints.down(790)); - const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = - useDisclosure(); - const { - isCropModalOpen, - openCropModal, - closeCropModal, - imageBlob, - originalImageUrl, - setCropModalImageBlob, - } = useCropModalState(); + const [isImageUploadOpen, openImageUploadModal, closeImageUploadModal] = useDisclosure(); + const { isCropModalOpen, openCropModal, closeCropModal, imageBlob, originalImageUrl, setCropModalImageBlob } = + useCropModalState(); const handleImageUpload = async (file: File) => { if (!selectedVariantId) return; setPictureUploading(true); - const url = await uploadQuestionImage( - question.id, - quizQid, - file, - (question, url) => { - if (!("variants" in question.content)) return; + const url = await uploadQuestionImage(question.id, quizQid, file, (question, url) => { + if (!("variants" in question.content)) return; - const variant = question.content.variants.find( - (variant) => variant.id === selectedVariantId, - ); - if (!variant) return; + const variant = question.content.variants.find((variant) => variant.id === selectedVariantId); + if (!variant) return; - variant.extendedText = url; - variant.originalImageUrl = url; - }, - ); + variant.extendedText = url; + variant.originalImageUrl = url; + }); closeImageUploadModal(); openCropModal(file, url); @@ -81,9 +58,7 @@ export default function OptionsPicture({ uploadQuestionImage(question.id, quizQid, imageBlob, (question, url) => { if (!("variants" in question.content)) return; - const variant = question.content.variants.find( - (variant) => variant.id === selectedVariantId, - ); + const variant = question.content.variants.find((variant) => variant.id === selectedVariantId); if (!variant) return; variant.extendedText = url; @@ -124,8 +99,7 @@ export default function OptionsPicture({ onClose={closeCropModal} onSaveImageClick={handleCropModalSaveClick} onDeleteClick={() => { - if (selectedVariantId) - clearQuestionImages(question.id, selectedVariantId); + if (selectedVariantId) clearQuestionImages(question.id, selectedVariantId); }} cropAspectRatio={{ width: 452, height: 300 }} /> @@ -167,10 +141,13 @@ export default function OptionsPicture({ questionId={question.id} questionContentId={question.content.id} questionType={question.type} - questionHasParent={question.content.rule.parentId.length !== 0} + questionHasParent={question.content.rule.parentId?.length !== 0} setOpenBranchingPage={setOpenBranchingPage} /> - + ); } diff --git a/src/pages/Questions/OptionsPicture/settingOpytionsPict.tsx b/src/pages/Questions/OptionsPicture/settingOpytionsPict.tsx index 770327db..d69dbf72 100644 --- a/src/pages/Questions/OptionsPicture/settingOpytionsPict.tsx +++ b/src/pages/Questions/OptionsPicture/settingOpytionsPict.tsx @@ -1,14 +1,13 @@ +import type { QuizQuestionImages, QuizQuestionVariant } from "@frontend/squzanswerer"; import { Box, Button, Typography, useMediaQuery, useTheme } from "@mui/material"; import { updateQuestion } from "@root/questions/actions"; import CustomCheckbox from "@ui_kit/CustomCheckbox"; +import { memo } from "react"; +import FormatIcon1 from "../../../assets/icons/questionsPage/FormatIcon1"; +import FormatIcon2 from "../../../assets/icons/questionsPage/FormatIcon2"; import ProportionsIcon11 from "../../../assets/icons/questionsPage/ProportionsIcon11"; import ProportionsIcon12 from "../../../assets/icons/questionsPage/ProportionsIcon12"; import ProportionsIcon21 from "../../../assets/icons/questionsPage/ProportionsIcon21"; -import type { QuizQuestionImages } from "../../../model/questionTypes/images"; -import { memo } from "react"; -import type { QuizQuestionVariant } from "@model/questionTypes/variant"; -import FormatIcon1 from "../../../assets/icons/questionsPage/FormatIcon1"; -import FormatIcon2 from "../../../assets/icons/questionsPage/FormatIcon2"; type Proportion = "1:1" | "2:1" | "1:2"; diff --git a/src/pages/Questions/OptionsPicture/switchOptionsPict.tsx b/src/pages/Questions/OptionsPicture/switchOptionsPict.tsx index 10f983a8..7a498c25 100644 --- a/src/pages/Questions/OptionsPicture/switchOptionsPict.tsx +++ b/src/pages/Questions/OptionsPicture/switchOptionsPict.tsx @@ -1,4 +1,4 @@ -import { QuizQuestionImages } from "@model/questionTypes/images"; +import { QuizQuestionImages } from "@frontend/squzanswerer"; import HelpQuestions from "../helpQuestions"; import SettingOpytionsPict from "./settingOpytionsPict"; diff --git a/src/pages/Questions/OwnTextField/OwnTextField.tsx b/src/pages/Questions/OwnTextField/OwnTextField.tsx index 9a381f01..92f96647 100644 --- a/src/pages/Questions/OwnTextField/OwnTextField.tsx +++ b/src/pages/Questions/OwnTextField/OwnTextField.tsx @@ -1,16 +1,10 @@ -import { - Box, - Tooltip, - Typography, - useMediaQuery, - useTheme, -} from "@mui/material"; +import { Box, Tooltip, Typography, useMediaQuery, useTheme } from "@mui/material"; import { updateQuestion } from "@root/questions/actions"; import CustomTextField from "@ui_kit/CustomTextField"; import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo"; import { useEffect, useState } from "react"; import InfoIcon from "../../../assets/icons/InfoIcon"; -import type { QuizQuestionText } from "../../../model/questionTypes/text"; +import type { QuizQuestionText } from "@frontend/squzanswerer"; import ButtonsOptionsAndPict from "../ButtonsOptionsAndPict"; import SwitchTextField from "./switchTextField"; @@ -20,11 +14,7 @@ interface Props { setOpenBranchingPage: (a: boolean) => void; } -export default function OwnTextField({ - question, - openBranchingPage, - setOpenBranchingPage, -}: Props) { +export default function OwnTextField({ question, openBranchingPage, setOpenBranchingPage }: Props) { const [switchState, setSwitchState] = useState("setting"); const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(790)); @@ -87,9 +77,7 @@ export default function OwnTextField({ Пользователю будет дано поле для ввода значения {isMobile ? ( - + ) : ( - + ); } diff --git a/src/pages/Questions/OwnTextField/settingTextField.tsx b/src/pages/Questions/OwnTextField/settingTextField.tsx index e085b262..2b34d70f 100644 --- a/src/pages/Questions/OwnTextField/settingTextField.tsx +++ b/src/pages/Questions/OwnTextField/settingTextField.tsx @@ -1,7 +1,7 @@ import { Box, FormControlLabel, Radio, RadioGroup, Typography, useMediaQuery, useTheme } from "@mui/material"; import { updateQuestion } from "@root/questions/actions"; import CustomCheckbox from "@ui_kit/CustomCheckbox"; -import type { QuizQuestionText } from "../../../model/questionTypes/text"; +import type { QuizQuestionText } from "@frontend/squzanswerer"; import { memo } from "react"; import RadioCheck from "@ui_kit/RadioCheck"; import RadioIcon from "@ui_kit/RadioIcon"; @@ -28,7 +28,6 @@ type SettingTextFieldProps = { const SettingTextField = memo(function ({ questionId, isRequired, isAutofill, answerType }) { const theme = useTheme(); - const isWrappColumn = useMediaQuery(theme.breakpoints.down(980)); const isMobile = useMediaQuery(theme.breakpoints.down(790)); const isTablet = useMediaQuery(theme.breakpoints.down(900)); const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990)); @@ -81,7 +80,12 @@ const SettingTextField = memo(function ({ questionId, isR {ANSWER_TYPES.map((answerTypeItem, index) => ( } icon={} />} + control={ + } + icon={} + /> + } label={answerTypeItem.name} sx={{ color: theme.palette.grey2.main, diff --git a/src/pages/Questions/OwnTextField/switchTextField.tsx b/src/pages/Questions/OwnTextField/switchTextField.tsx index 779620bf..d712c9d0 100644 --- a/src/pages/Questions/OwnTextField/switchTextField.tsx +++ b/src/pages/Questions/OwnTextField/switchTextField.tsx @@ -1,4 +1,4 @@ -import { QuizQuestionText } from "@model/questionTypes/text"; +import { QuizQuestionText } from "@frontend/squzanswerer"; import HelpQuestions from "../helpQuestions"; import SettingTextField from "./settingTextField"; import UploadImage from "../UploadImage"; @@ -16,12 +16,16 @@ export default function SwitchTextField({ switchState = "setting", question }: P questionId={question.id} isRequired={question.content.required} isAutofill={question.content.autofill} - isOnlyNumbers={question.content.onlyNumbers} answerType={question.content.answerType} /> ); case "image": - return ; + return ( + + ); case "help": return ( - DeleteFunction(question.id), - ); + deleteQuestionWithTimeout(question.id, () => DeleteFunction(question.id)); } }} data-cy="delete-question" > - setOpenDelete(false)}> + setOpenDelete(false)} + > - - Вы удаляете вопрос, участвующий в ветвлении. Все его потомки - потеряют данные ветвления. Вы уверены, что хотите удалить - вопрос? + + Вы удаляете вопрос, участвующий в ветвлении. Все его потомки потеряют данные ветвления. Вы уверены, что + хотите удалить вопрос? { - deleteQuestionWithTimeout(question.id, () => - DeleteFunction(question.id), - ); + deleteQuestionWithTimeout(question.id, () => DeleteFunction(question.id)); }} > Подтвердить diff --git a/src/pages/Questions/PageOptions/SettingPageOptions.tsx b/src/pages/Questions/PageOptions/SettingPageOptions.tsx index c219a2f7..123fa8fa 100644 --- a/src/pages/Questions/PageOptions/SettingPageOptions.tsx +++ b/src/pages/Questions/PageOptions/SettingPageOptions.tsx @@ -1,13 +1,11 @@ import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; -import type { QuizQuestionPage } from "../../../model/questionTypes/page"; +import type { QuizQuestionPage } from "@frontend/squzanswerer"; type SettingPageOptionsProps = { question: QuizQuestionPage; }; -export default function SettingPageOptions({ - question, -}: SettingPageOptionsProps) { +export default function SettingPageOptions({ question }: SettingPageOptionsProps) { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down(790)); diff --git a/src/pages/Questions/PageOptions/switchPageOptions.tsx b/src/pages/Questions/PageOptions/switchPageOptions.tsx index 0680b8cf..bb0c9125 100644 --- a/src/pages/Questions/PageOptions/switchPageOptions.tsx +++ b/src/pages/Questions/PageOptions/switchPageOptions.tsx @@ -1,4 +1,4 @@ -import { QuizQuestionPage } from "@model/questionTypes/page"; +import { QuizQuestionPage } from "@frontend/squzanswerer"; import HelpQuestions from "../helpQuestions"; import SettingPageOptions from "./SettingPageOptions"; @@ -7,10 +7,7 @@ interface Props { question: QuizQuestionPage; } -export default function SwitchPageOptions({ - switchState = "setting", - question, -}: Props) { +export default function SwitchPageOptions({ switchState = "setting", question }: Props) { switch (switchState) { case "setting": return ; diff --git a/src/pages/Questions/RatingOptions/RatingOptions.tsx b/src/pages/Questions/RatingOptions/RatingOptions.tsx index 56d441bf..fd6e9918 100644 --- a/src/pages/Questions/RatingOptions/RatingOptions.tsx +++ b/src/pages/Questions/RatingOptions/RatingOptions.tsx @@ -1,11 +1,4 @@ -import { - Box, - TextField as MuiTextField, - TextFieldProps, - Typography, - useMediaQuery, - useTheme, -} from "@mui/material"; +import { Box, TextField as MuiTextField, TextFieldProps, Typography, useMediaQuery, useTheme } from "@mui/material"; import { updateQuestion } from "@root/questions/actions"; import { FC, useLayoutEffect, useRef, useState } from "react"; import FlagIcon from "../../../assets/icons/questionsPage/FlagIcon"; @@ -15,7 +8,7 @@ import HeartIcon from "../../../assets/icons/questionsPage/heartIcon"; import LightbulbIcon from "../../../assets/icons/questionsPage/lightbulbIcon"; import LikeIcon from "../../../assets/icons/questionsPage/likeIcon"; import TropfyIcon from "../../../assets/icons/questionsPage/tropfyIcon"; -import type { QuizQuestionRating } from "../../../model/questionTypes/rating"; +import type { QuizQuestionRating } from "@frontend/squzanswerer"; import ButtonsOptions from "../ButtonsOptions"; import SwitchRating from "./switchRating"; @@ -32,11 +25,7 @@ export type ButtonRatingFrom = { icon: JSX.Element; }; -export default function RatingOptions({ - question, - openBranchingPage, - setOpenBranchingPage, -}: Props) { +export default function RatingOptions({ question, openBranchingPage, setOpenBranchingPage }: Props) { const [switchState, setSwitchState] = useState("setting"); const [negativeTextWidth, setNegativeTextWidth] = useState(0); const [positiveTextWidth, setPositiveTextWidth] = useState(0); @@ -156,10 +145,7 @@ export default function RatingOptions({ gap: isMobile ? "8px" : "30px", }} > - {Array.from( - { length: question.content.steps }, - (_, index) => index, - ).map((itemNumber) => ( + {Array.from({ length: question.content.steps }, (_, index) => index).map((itemNumber) => ( - { - buttonRatingForm.find( - ({ name }) => question.content.form === name, - )?.icon - } + {buttonRatingForm.find(({ name }) => question.content.form === name)?.icon} ))} @@ -311,10 +293,13 @@ export default function RatingOptions({ questionId={question.id} questionContentId={question.content.id} questionType={question.type} - questionHasParent={question.content.rule.parentId.length !== 0} + questionHasParent={question.content.rule.parentId?.length !== 0} setOpenBranchingPage={setOpenBranchingPage} /> - + ); } diff --git a/src/pages/Questions/RatingOptions/settingRating.tsx b/src/pages/Questions/RatingOptions/settingRating.tsx index 6b8b79d7..341932da 100644 --- a/src/pages/Questions/RatingOptions/settingRating.tsx +++ b/src/pages/Questions/RatingOptions/settingRating.tsx @@ -1,12 +1,5 @@ -import { QuizQuestionRating } from "@model/questionTypes/rating"; -import { - Box, - ButtonBase, - Slider, - Typography, - useMediaQuery, - useTheme, -} from "@mui/material"; +import { QuizQuestionRating } from "@frontend/squzanswerer"; +import { Box, ButtonBase, Slider, Typography, useMediaQuery, useTheme } from "@mui/material"; import { updateQuestion } from "@root/questions/actions"; import CustomCheckbox from "@ui_kit/CustomCheckbox"; import FlagIcon from "../../../assets/icons/questionsPage/FlagIcon"; @@ -92,14 +85,8 @@ export default function SettingSlider({ question }: SettingSliderProps) { }); }} sx={{ - backgroundColor: - question.content.form === name - ? theme.palette.brightPurple.main - : "transparent", - color: - question.content.form === name - ? "#ffffff" - : theme.palette.grey3.main, + backgroundColor: question.content.form === name ? theme.palette.brightPurple.main : "transparent", + color: question.content.form === name ? "#ffffff" : theme.palette.grey3.main, width: "40px", height: "40px", borderRadius: "4px", diff --git a/src/pages/Questions/RatingOptions/switchRating.tsx b/src/pages/Questions/RatingOptions/switchRating.tsx index 7fd172c0..9cbaaccd 100644 --- a/src/pages/Questions/RatingOptions/switchRating.tsx +++ b/src/pages/Questions/RatingOptions/switchRating.tsx @@ -1,4 +1,4 @@ -import { QuizQuestionRating } from "@model/questionTypes/rating"; +import { QuizQuestionRating } from "@frontend/squzanswerer"; import HelpQuestions from "../helpQuestions"; import SettingRating from "./settingRating"; @@ -7,10 +7,7 @@ interface Props { question: QuizQuestionRating; } -export default function SwitchRating({ - switchState = "setting", - question, -}: Props) { +export default function SwitchRating({ switchState = "setting", question }: Props) { switch (switchState) { case "setting": return ; diff --git a/src/pages/Questions/SliderOptions/SliderOptions.tsx b/src/pages/Questions/SliderOptions/SliderOptions.tsx index 7e8a3fd8..65343524 100644 --- a/src/pages/Questions/SliderOptions/SliderOptions.tsx +++ b/src/pages/Questions/SliderOptions/SliderOptions.tsx @@ -9,7 +9,7 @@ import SwitchSlider from "./switchSlider"; import { updateQuestion } from "@root/questions/actions"; -import type { QuizQuestionNumber } from "../../../model/questionTypes/number"; +import type { QuizQuestionNumber } from "@frontend/squzanswerer"; interface Props { question: QuizQuestionNumber; @@ -17,11 +17,7 @@ interface Props { setOpenBranchingPage: (a: boolean) => void; } -export default function SliderOptions({ - question, - openBranchingPage, - setOpenBranchingPage, -}: Props) { +export default function SliderOptions({ question, openBranchingPage, setOpenBranchingPage }: Props) { const theme = useTheme(); const isTablet = useMediaQuery(theme.breakpoints.down(980)); const isMobile = useMediaQuery(theme.breakpoints.down(790)); @@ -74,11 +70,7 @@ export default function SliderOptions({ } if (range % step) { - setStepError( - `Шаг должен делить без остатка диапазон ${maxBorder} - ${minBorder} = ${ - maxBorder - minBorder - }`, - ); + setStepError(`Шаг должен делить без остатка диапазон ${maxBorder} - ${minBorder} = ${maxBorder - minBorder}`); updateStepDebounced(1); } }; @@ -106,9 +98,7 @@ export default function SliderOptions({ marginRight: isMobile ? "10px" : "0px", }} > - + Выбор значения из диапазона { updateQuestion(question.id, (question) => { - question.content.range = `${target.value}—${ - question.content.range.split("—")[1] - }`; + question.content.range = `${target.value}—${question.content.range.split("—")[1]}`; }); }} onBlur={calculateValues} @@ -143,9 +131,7 @@ export default function SliderOptions({ value={question.content.range.split("—")[1]} onChange={({ target }) => { updateQuestion(question.id, (question) => { - question.content.range = `${ - question.content.range.split("—")[0] - }—${target.value}`; + question.content.range = `${question.content.range.split("—")[0]}—${target.value}`; }); }} onBlur={calculateValues} @@ -227,10 +213,13 @@ export default function SliderOptions({ questionId={question.id} questionContentId={question.content.id} questionType={question.type} - questionHasParent={question.content.rule.parentId.length !== 0} + questionHasParent={question.content.rule.parentId?.length !== 0} setOpenBranchingPage={setOpenBranchingPage} /> - + ); } diff --git a/src/pages/Questions/SliderOptions/settingSlider.tsx b/src/pages/Questions/SliderOptions/settingSlider.tsx index 7ad9d712..cd81c2a1 100644 --- a/src/pages/Questions/SliderOptions/settingSlider.tsx +++ b/src/pages/Questions/SliderOptions/settingSlider.tsx @@ -1,7 +1,7 @@ import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; import { updateQuestion } from "@root/questions/actions"; import CustomCheckbox from "@ui_kit/CustomCheckbox"; -import type { QuizQuestionNumber } from "../../../model/questionTypes/number"; +import type { QuizQuestionNumber } from "@frontend/squzanswerer"; type SettingSliderProps = { question: QuizQuestionNumber; diff --git a/src/pages/Questions/SliderOptions/switchSlider.tsx b/src/pages/Questions/SliderOptions/switchSlider.tsx index ba03a6ff..a97c48c7 100644 --- a/src/pages/Questions/SliderOptions/switchSlider.tsx +++ b/src/pages/Questions/SliderOptions/switchSlider.tsx @@ -1,4 +1,4 @@ -import { QuizQuestionNumber } from "@model/questionTypes/number"; +import { QuizQuestionNumber } from "@frontend/squzanswerer"; import HelpQuestions from "../helpQuestions"; import SettingSlider from "./settingSlider"; @@ -7,10 +7,7 @@ interface Props { question: QuizQuestionNumber; } -export default function SwitchSlider({ - switchState = "setting", - question, -}: Props) { +export default function SwitchSlider({ switchState = "setting", question }: Props) { switch (switchState) { case "setting": return ; diff --git a/src/pages/Questions/SwitchBranchingPanel/QuestionsList.tsx b/src/pages/Questions/SwitchBranchingPanel/QuestionsList.tsx index 5950ac00..c8f62016 100644 --- a/src/pages/Questions/SwitchBranchingPanel/QuestionsList.tsx +++ b/src/pages/Questions/SwitchBranchingPanel/QuestionsList.tsx @@ -1,18 +1,12 @@ -import { useParams } from "react-router-dom"; -import { Box, Button, IconButton, Typography } from "@mui/material"; +import { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; import { ReactComponent as CheckedIcon } from "@icons/checked.svg"; +import { UntypedQuizQuestion } from "@model/questionTypes/shared"; +import { Box, Button, IconButton, Typography } from "@mui/material"; import { useQuestionsStore } from "@root/questions/store"; -import { useEffect } from "react"; -import { - AnyTypedQuizQuestion, - UntypedQuizQuestion, -} from "@model/questionTypes/shared"; -import { Pencil } from "../../../ui_kit/Sidebar/icons/Pencil"; -import { - updateEditSomeQuestion, - updateDragQuestionContentId, -} from "@root/uiTools/actions"; +import { updateDragQuestionContentId, updateEditSomeQuestion } from "@root/uiTools/actions"; import { useUiTools } from "@root/uiTools/store"; +import { useEffect } from "react"; +import { Pencil } from "../../../ui_kit/Sidebar/icons/Pencil"; const getItemStyle = (isDragging: any, draggableStyle: any) => ({ userSelect: "none", @@ -32,9 +26,7 @@ interface Props { export const QuestionsList = ({ setOpenBranchingPage = () => {} }: Props) => { const { desireToOpenABranchingModal } = useUiTools(); const trashQuestions = useQuestionsStore().questions; - const questions = trashQuestions.filter( - (question) => question.type !== "result", - ); + const questions = trashQuestions.filter((question) => question.type !== "result"); useEffect(() => { if (desireToOpenABranchingModal) { @@ -73,8 +65,7 @@ export const QuestionsList = ({ setOpenBranchingPage = () => {} }: Props) => { id={content.id} onMouseDown={() => { //Разрешаем добавить этот вопрос если у него нет родителя (не добавляли ещё в дерево) - if (!content.rule.parentId) - updateDragQuestionContentId(content.id); + if (!content.rule.parentId) updateDragQuestionContentId(content.id); }} key={index} sx={{ @@ -86,10 +77,7 @@ export const QuestionsList = ({ setOpenBranchingPage = () => {} }: Props) => { padding: "12px", background: "#FFFFFF", borderRadius: "8px", - border: - desireToOpenABranchingModal === content.id - ? "4px solid #7e2aea" - : "none", + border: desireToOpenABranchingModal === content.id ? "4px solid #7e2aea" : "none", marginBottom: "20px", boxShadow: "0px 10px 30px #e7e7e7", backgroundImage: `url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' rx='8' ry='8' stroke='rgb(154, 154, 175)' strokeWidth='2' stroke-dasharray='8 8' stroke-dashoffset='0' strokeLinecap='square'/%3e%3c/svg%3e"); diff --git a/src/pages/Questions/SwitchQuestionsPage.tsx b/src/pages/Questions/SwitchQuestionsPage.tsx index 2d20bb4d..602f73c1 100644 --- a/src/pages/Questions/SwitchQuestionsPage.tsx +++ b/src/pages/Questions/SwitchQuestionsPage.tsx @@ -1,4 +1,3 @@ -import { AnyTypedQuizQuestion } from "@model/questionTypes/shared"; import DataOptions from "./DataOptions/DataOptions"; import DropDown from "./DropDown/DropDown"; import Emoji from "./Emoji/Emoji"; @@ -11,6 +10,7 @@ import SliderOptions from "./SliderOptions/SliderOptions"; import UploadFile from "./UploadFile/UploadFile"; import AnswerOptions from "./answerOptions/AnswerOptions"; import { notReachable } from "../../utils/notReachable"; +import { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; interface Props { question: AnyTypedQuizQuestion; @@ -18,11 +18,7 @@ interface Props { setOpenBranchingPage: (a: boolean) => void; } -export default function SwitchQuestionsPage({ - question, - openBranchingPage, - setOpenBranchingPage, -}: Props) { +export default function SwitchQuestionsPage({ question, openBranchingPage, setOpenBranchingPage }: Props) { switch (question.type) { case "variant": return ( diff --git a/src/pages/Questions/UploadFile/UploadFile.tsx b/src/pages/Questions/UploadFile/UploadFile.tsx index 74f73412..013b9bda 100644 --- a/src/pages/Questions/UploadFile/UploadFile.tsx +++ b/src/pages/Questions/UploadFile/UploadFile.tsx @@ -13,13 +13,10 @@ import { updateQuestion } from "@root/questions/actions"; import { useEffect, useState } from "react"; import ArrowDown from "../../../assets/icons/ArrowDownIcon"; import InfoIcon from "../../../assets/icons/InfoIcon"; -import type { - QuizQuestionFile, - UploadFileType, -} from "../../../model/questionTypes/file"; import ButtonsOptions from "../ButtonsOptions"; import SwitchUpload from "./switchUpload"; import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo"; +import { QuizQuestionFile, UploadFileType } from "@frontend/squzanswerer"; type DesignItem = { name: string; @@ -39,11 +36,7 @@ interface Props { setOpenBranchingPage: (a: boolean) => void; } -export default function UploadFile({ - question, - openBranchingPage, - setOpenBranchingPage, -}: Props) { +export default function UploadFile({ question, openBranchingPage, setOpenBranchingPage }: Props) { const [switchState, setSwitchState] = useState("setting"); const theme = useTheme(); const isTablet = useMediaQuery(theme.breakpoints.down(980)); @@ -59,9 +52,7 @@ export default function UploadFile({ }; useEffect(() => { - const isTypeSetted = DESIGN_TYPES.find( - ({ value }) => value === question.content.type, - ); + const isTypeSetted = DESIGN_TYPES.find(({ value }) => value === question.content.type); if (!isTypeSetted) { updateQuestion(question.id, (question) => { @@ -83,9 +74,7 @@ export default function UploadFile({ flexDirection: "column", }} > - + {isMobile ? ( - + ) : ( - + ); } diff --git a/src/pages/Questions/UploadFile/settingUpload.tsx b/src/pages/Questions/UploadFile/settingUpload.tsx index 8c82c726..b1e84299 100644 --- a/src/pages/Questions/UploadFile/settingUpload.tsx +++ b/src/pages/Questions/UploadFile/settingUpload.tsx @@ -1,7 +1,7 @@ import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; import { updateQuestion } from "@root/questions/actions"; import CustomCheckbox from "@ui_kit/CustomCheckbox"; -import type { QuizQuestionFile } from "../../../model/questionTypes/file"; +import type { QuizQuestionFile } from "@frontend/squzanswerer"; type SettingsUploadProps = { question: QuizQuestionFile; diff --git a/src/pages/Questions/UploadFile/switchUpload.tsx b/src/pages/Questions/UploadFile/switchUpload.tsx index f105e055..9b5f6138 100644 --- a/src/pages/Questions/UploadFile/switchUpload.tsx +++ b/src/pages/Questions/UploadFile/switchUpload.tsx @@ -1,4 +1,4 @@ -import { QuizQuestionFile } from "@model/questionTypes/file"; +import { QuizQuestionFile } from "@frontend/squzanswerer"; import HelpQuestions from "../helpQuestions"; import SettingsUpload from "./settingUpload"; @@ -7,10 +7,7 @@ interface Props { question: QuizQuestionFile; } -export default function SwitchUpload({ - switchState = "setting", - question, -}: Props) { +export default function SwitchUpload({ switchState = "setting", question }: Props) { switch (switchState) { case "setting": return ; diff --git a/src/pages/Questions/UploadImage/index.tsx b/src/pages/Questions/UploadImage/index.tsx index 2c87f6f8..171e6d48 100644 --- a/src/pages/Questions/UploadImage/index.tsx +++ b/src/pages/Questions/UploadImage/index.tsx @@ -1,4 +1,4 @@ -import { AnyTypedQuizQuestion } from "@model/questionTypes/shared"; +import { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; import { Box, Skeleton, Typography, useTheme } from "@mui/material"; import { updateQuestion, uploadQuestionImage } from "@root/questions/actions"; import { useCurrentQuiz } from "@root/quizes/hooks"; @@ -13,10 +13,7 @@ type UploadImageProps = { }; }; -export default function UploadImage({ - question, - cropAspectRatio, -}: UploadImageProps) { +export default function UploadImage({ question, cropAspectRatio }: UploadImageProps) { const [pictureUploding, setPictureUploading] = useState(false); const theme = useTheme(); const quiz = useCurrentQuiz(); @@ -36,7 +33,10 @@ export default function UploadImage({ Загрузить изображение {pictureUploding ? ( - + ) : ( { setPictureUploading(true); - await uploadQuestionImage( - question.id, - quiz.qid, - file, - (question, url) => { - question.content.back = url; - question.content.originalBack = url; - }, - ); + await uploadQuestionImage(question.id, quiz.qid, file, (question, url) => { + question.content.back = url; + question.content.originalBack = url; + }); setPictureUploading(false); }} @@ -67,14 +62,9 @@ export default function UploadImage({ onImageSaveClick={async (file) => { setPictureUploading(true); - await uploadQuestionImage( - question.id, - quiz.qid, - file, - (question, url) => { - question.content.back = url; - }, - ); + await uploadQuestionImage(question.id, quiz.qid, file, (question, url) => { + question.content.back = url; + }); setPictureUploading(false); }} diff --git a/src/pages/Questions/answerOptions/AnswerOptions.tsx b/src/pages/Questions/answerOptions/AnswerOptions.tsx index 87062da6..dc49b310 100755 --- a/src/pages/Questions/answerOptions/AnswerOptions.tsx +++ b/src/pages/Questions/answerOptions/AnswerOptions.tsx @@ -1,7 +1,7 @@ import { Box, Link, Typography, useMediaQuery, useTheme } from "@mui/material"; import { useEffect, useState } from "react"; import { EnterIcon } from "../../../assets/icons/questionsPage/enterIcon"; -import type { QuizQuestionVariant } from "../../../model/questionTypes/variant"; +import type { QuizQuestionVariant } from "@frontend/squzanswerer"; import { useAddAnswer } from "../../../utils/hooks/useAddAnswer"; import { AnswerDraggableList } from "../AnswerDraggableList"; import AnswerItem from "../AnswerDraggableList/AnswerItem"; @@ -14,11 +14,7 @@ interface Props { setOpenBranchingPage: (a: boolean) => void; } -export default function AnswerOptions({ - question, - openBranchingPage, - setOpenBranchingPage, -}: Props) { +export default function AnswerOptions({ question, openBranchingPage, setOpenBranchingPage }: Props) { const onClickAddAnAnswer = useAddAnswer(); const [switchState, setSwitchState] = useState("setting"); const theme = useTheme(); @@ -109,12 +105,15 @@ export default function AnswerOptions({ SSHC={setSwitchState} questionId={question.id} questionContentId={question.content.id} - questionHasParent={question.content.rule.parentId.length !== 0} + questionHasParent={question.content.rule.parentId?.length !== 0} questionType={question.type} openBranchingPage={openBranchingPage} setOpenBranchingPage={setOpenBranchingPage} /> - + ); } diff --git a/src/pages/Questions/answerOptions/responseSettings.tsx b/src/pages/Questions/answerOptions/responseSettings.tsx index f645c3cc..e57cd4ca 100644 --- a/src/pages/Questions/answerOptions/responseSettings.tsx +++ b/src/pages/Questions/answerOptions/responseSettings.tsx @@ -1,7 +1,7 @@ import { Box, Typography, useMediaQuery, useTheme } from "@mui/material"; import { updateQuestion } from "@root/questions/actions"; import CustomCheckbox from "@ui_kit/CustomCheckbox"; -import type { QuizQuestionVariant } from "../../../model/questionTypes/variant"; +import type { QuizQuestionVariant } from "@frontend/squzanswerer"; import { memo } from "react"; interface Props { diff --git a/src/pages/Questions/answerOptions/switchAnswerOptions.tsx b/src/pages/Questions/answerOptions/switchAnswerOptions.tsx index 89d2cff7..348c7fac 100644 --- a/src/pages/Questions/answerOptions/switchAnswerOptions.tsx +++ b/src/pages/Questions/answerOptions/switchAnswerOptions.tsx @@ -1,4 +1,4 @@ -import { QuizQuestionVariant } from "@model/questionTypes/variant"; +import { QuizQuestionVariant } from "@frontend/squzanswerer"; import UploadImage from "../UploadImage"; import HelpQuestions from "../helpQuestions"; import ResponseSettings from "./responseSettings"; @@ -29,7 +29,12 @@ export default function SwitchAnswerOptions({ switchState = "setting", question /> ); case "image": - return ; + return ( + + ); default: return null; } diff --git a/src/pages/QuizAnswersPage/CardAnswer.tsx b/src/pages/QuizAnswersPage/CardAnswer.tsx index 685d42b8..533a1645 100644 --- a/src/pages/QuizAnswersPage/CardAnswer.tsx +++ b/src/pages/QuizAnswersPage/CardAnswer.tsx @@ -1,12 +1,5 @@ import { ArrowDownIcon } from "@icons/questionsPage/ArrowDownIcon"; -import { - Box, - IconButton, - Link, - Typography, - useMediaQuery, - useTheme, -} from "@mui/material"; +import { Box, IconButton, Link, Typography, useMediaQuery, useTheme } from "@mui/material"; import { FC, MouseEvent, useState } from "react"; import { ContactIcon } from "./icons/ContactIcon"; import { MessageIcon } from "./icons/MessageIcon"; @@ -21,7 +14,7 @@ import AddressIcon from "@icons/ContactFormIcon/AddressIcon"; import { DeleteModal } from "./DeleteModal"; -import type { AnyTypedQuizQuestion } from "@model/questionTypes/shared"; +import type { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; interface CardAnswerProps { isNew: boolean; @@ -51,9 +44,7 @@ export const CardAnswer: FC = ({ const theme = useTheme(); const isTablet = useMediaQuery(theme.breakpoints.down(1000)); const [resultsAnswer, setResultsAnswer] = useState([]); - const [questionsResultState, setQuestionsResultState] = useState< - AnyTypedQuizQuestion[] - >([]); + const [questionsResultState, setQuestionsResultState] = useState([]); const { editQuizId } = useQuizStore(); const { questions } = useQuestionsStore(); const openResults = async () => { @@ -73,9 +64,7 @@ export const CardAnswer: FC = ({ const resQuiz = resAnswer.filter((res) => res.Result === true); setResultsAnswer(resAnswerOnly); const idResults = resQuiz[0].question_id; - const questionsResult = questions.filter( - (q) => q.type && q.backendId === idResults, - ) as AnyTypedQuizQuestion[]; + const questionsResult = questions.filter((q) => q.type && q.backendId === idResults) as AnyTypedQuizQuestion[]; setQuestionsResultState(questionsResult); } @@ -116,11 +105,7 @@ export const CardAnswer: FC = ({ flexDirection: isTablet ? "column" : "-moz-initial", cursor: "pointer", p: "20px", - borderRadius: isTablet - ? "12px 12px 0 0" - : isOpen - ? "12px 0 0 0" - : "12px 0 0 12px", + borderRadius: isTablet ? "12px 12px 0 0" : isOpen ? "12px 0 0 0" : "12px 0 0 12px", display: "flex", alignItems: "flex-start", background: "#FFF", @@ -136,9 +121,7 @@ export const CardAnswer: FC = ({ justifyContent: isTablet ? "space-between" : "-moz-initial", pb: isTablet ? "20px" : "0", mb: isTablet ? "20px" : "0", - borderBottom: isTablet - ? "1px solid rgba(154, 154, 175, 0.50)" - : "0", + borderBottom: isTablet ? "1px solid rgba(154, 154, 175, 0.50)" : "0", }} > @@ -182,43 +165,27 @@ export const CardAnswer: FC = ({ {name && ( - + - - {name} - + {name} )} {email && ( - + - - {email} - + {email} )} {phone && ( - + - - {phone} - + {phone} )} {address && ( - + - - {address} - + {address} )} @@ -272,13 +239,19 @@ export const CardAnswer: FC = ({ - + ) : ( - + )} @@ -302,9 +275,7 @@ export const CardAnswer: FC = ({ borderRadius: "0 0 12px 12px", }} > - - Ответы - + Ответы = ({ > )} {typeQuestionFile === "picture" && ( - + )} клик для скачивания )} - {(typeOuestion === "images" || - typeOuestion === "varimg") && ( + {(typeOuestion === "images" || typeOuestion === "varimg") && ( <> ')[0] - } + src={answer.content.split("<")[1].split('src="')[1].split('"/>')[0]} /> - - {answer.content.split("<")[0]} - + {answer.content.split("<")[0]} )} - {!( - typeOuestion === "file" || - typeOuestion === "images" || - typeOuestion === "varimg" - ) && ( - - {answer.content} - + {!(typeOuestion === "file" || typeOuestion === "images" || typeOuestion === "varimg") && ( + {answer.content} )} ); @@ -414,9 +375,7 @@ export const CardAnswer: FC = ({ borderRadius: "0 0 12px 12px", }} > - - Результаты - + Результаты {questionsResultState.map((res) => { return ( @@ -438,28 +397,20 @@ export const CardAnswer: FC = ({ > {res.description} - - {res.title} - - {res.content.useImage && - res.content.back && - res.content.back !== " " && ( - {""} - )} - {!res.content.useImage && - res.content.back && - res.content.back !== " " && ( - - )} + {res.title} + {res.content.useImage && res.content.back && res.content.back !== " " && ( + {""} + )} + {!res.content.useImage && res.content.back && res.content.back !== " " && ( + + )} ); })} diff --git a/src/pages/ResultPage/ResultSettings.tsx b/src/pages/ResultPage/ResultSettings.tsx index ddc0b177..df0cef92 100644 --- a/src/pages/ResultPage/ResultSettings.tsx +++ b/src/pages/ResultPage/ResultSettings.tsx @@ -1,51 +1,17 @@ -import { useEffect, useRef, useState } from "react"; -import { - Box, - Button, - Typography, - Paper, - Modal, - TextField, -} from "@mui/material"; -import { incrementCurrentStep } from "@root/quizes/actions"; -import CustomWrapper from "@ui_kit/CustomWrapper"; -import { DescriptionForm } from "./DescriptionForm/DescriptionForm"; -import { ResultListForm } from "./ResultListForm"; -import { SettingForm } from "./SettingForm"; -import { WhenCard } from "./cards/WhenCard"; -import { ResultCard, checkEmptyData } from "./cards/ResultCard"; -import { EmailSettingsCard } from "./cards/EmailSettingsCard"; -import { useCurrentQuiz } from "@root/quizes/hooks"; +import { QuizQuestionResult } from "@frontend/squzanswerer"; +import { Box, Button, Modal, Typography } from "@mui/material"; import { useQuestionsStore } from "@root/questions/store"; -import { - createResult, - deleteQuestion, - setQuestions, -} from "@root/questions/actions"; -import { QuizQuestionResult } from "@model/questionTypes/result"; - -import IconPlus from "@icons/IconPlus"; -import Info from "@icons/Info"; -import Plus from "@icons/Plus"; -import ArrowLeft from "@icons/questionsPage/arrowLeft"; -import { useNavigate } from "react-router-dom"; -import { questionApi } from "@api/question"; +import { useCurrentQuiz } from "@root/quizes/hooks"; +import { useEffect, useRef, useState } from "react"; +import { EmailSettingsCard } from "./cards/EmailSettingsCard"; +import { ResultCard, checkEmptyData } from "./cards/ResultCard"; +import { WhenCard } from "./cards/WhenCard"; export const ResultSettings = () => { - const { questions } = useQuestionsStore(); const quiz = useCurrentQuiz(); - const navigate = useNavigate(); - const results = useQuestionsStore().questions.filter( - (q): q is QuizQuestionResult => q.type === "result", - ); + const results = useQuestionsStore().questions.filter((q): q is QuizQuestionResult => q.type === "result"); const [quizExpand, setQuizExpand] = useState(true); const [resultContract, setResultContract] = useState(true); - const [triggerExit, setTriggerExit] = useState<{ - follow: boolean; - path: string; - }>({ follow: false, path: "" }); - const [openNotificationModal, setOpenNotificationModal] = - useState(true); const isReadyToLeaveRef = useRef(true); useEffect( @@ -58,20 +24,11 @@ export const ResultSettings = () => { }); isReadyToLeaveRef.current = isReadyToLeave; }, - [results], + [results] ); const cnsl = results.filter((q) => q.content.usage); - const shouldBlock = true; - - const leavePage = (leave: boolean) => { - if (leave) { - } - - setOpenNotificationModal(false); - }; - return ( { - {quiz?.config.resultInfo.when === "email" && ( - - )} + {quiz?.config.resultInfo.when === "email" && } - - + + Создайте результат @@ -112,12 +84,7 @@ export const MediaSelectionAndDisplay: FC = ({ }, }} variant="text" - onClick={() => - updateQuestion( - resultData.id, - (question) => (question.content.useImage = false), - ) - } + onClick={() => updateQuestion(resultData.id, (question) => (question.content.useImage = false))} > Видео @@ -166,10 +133,7 @@ export const MediaSelectionAndDisplay: FC = ({ uploading={pictureUploding} onImageClick={() => { if (resultData.content.back) { - return openCropModal( - resultData.content.back, - resultData.content.originalBack, - ); + return openCropModal(resultData.content.back, resultData.content.originalBack); } openImageUploadModal(); @@ -193,12 +157,11 @@ export const MediaSelectionAndDisplay: FC = ({ mb: "14px", }} > - Добавить видео + - Добавить видео - - @@ -231,14 +194,9 @@ export const MediaSelectionAndDisplay: FC = ({ setBackgroundUploading(true); const file = event.target.files?.[0]; if (file) { - await uploadQuestionImage( - resultData.id, - quizQid, - file, - (question, url) => { - question.content.video = url; - }, - ); + await uploadQuestionImage(resultData.id, quizQid, file, (question, url) => { + question.content.video = url; + }); } setBackgroundUploading(false); }} diff --git a/src/ui_kit/QuizPreview/QuizPreview.tsx b/src/ui_kit/QuizPreview/QuizPreview.tsx index abcfbe5e..9c71aa8f 100644 --- a/src/ui_kit/QuizPreview/QuizPreview.tsx +++ b/src/ui_kit/QuizPreview/QuizPreview.tsx @@ -1,6 +1,6 @@ import { QuizAnswerer } from "@frontend/squzanswerer"; import ResizeIcon from "@icons/ResizeIcon"; -import { AnyTypedQuizQuestion } from "@model/questionTypes/shared"; +import { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; import { Box, ThemeProvider } from "@mui/material"; import { useQuestionsStore } from "@root/questions/store"; import { useQuizPreviewStore } from "@root/quizPreview"; @@ -21,7 +21,7 @@ export default function QuizPreview() { const rndParentRef = useRef(null); const quiz = useCurrentQuiz(); const questions = useQuestionsStore((state) => state.questions).filter( - (q): q is AnyTypedQuizQuestion => q.type !== null, + (q): q is AnyTypedQuizQuestion => q.type !== null ); const rndRef = useRef(null); const rndPositionAndSizeRef = useRef({ @@ -38,13 +38,7 @@ export default function QuizPreview() { function stickPreviewToBottomRight() { const rnd = rndRef.current; const rndSelfElement = rnd?.getSelfElement(); - if ( - !rnd || - !rndSelfElement || - !rndParentRef.current || - !isFirstShowRef.current - ) - return; + if (!rnd || !rndSelfElement || !rndParentRef.current || !isFirstShowRef.current) return; const rndParentRect = rndParentRef.current.getBoundingClientRect(); const rndRect = rndSelfElement.getBoundingClientRect(); @@ -58,13 +52,11 @@ export default function QuizPreview() { isFirstShowRef.current = false; }, - [isPreviewShown], + [isPreviewShown] ); return ( - + => { const problems: any = {}; @@ -35,12 +29,7 @@ export const checkQuestionHint = ( questions.forEach((question: AnyTypedQuizQuestion) => { //Если не участвует в ветвлении, или безтиповый, или резулт - он нам не интересен - if ( - question.type === null || - question.type === "result" || - question.content.rule.parentId.length === 0 - ) - return; + if (question.type === null || question.type === "result" || question.content.rule.parentId?.length === 0) return; if ( question?.type === "date" || @@ -50,52 +39,40 @@ export const checkQuestionHint = ( ) { //Если у вопроса типа страница, ползунок, своё поле для ввода и дата есть ребёнок, но нет дефолта - молча его добавляем. - if ( - question.content.rule.children.length === 1 && - question.content.rule.default.length === 0 - ) + if (question.content.rule.children.length === 1 && question.content.rule.default.length === 0) updateQuestion(question.id, (q) => { question.content.rule.default = question.content.rule.children[0]; }); } else { //если есть дети, но нет дефолта - логическая ошибка. Так нельзя - if ( - question.content.rule.children.length > 0 && - question.content.rule.default.length === 0 - ) { - pushProblem( - question.content.id, - "Не выбран дефолтный вопрос", - question.title, - ); + if (question.content.rule.children.length > 0 && question.content.rule.default.length === 0) { + pushProblem(question.content.id, "Не выбран дефолтный вопрос", question.title); } } //Rules вопроса не должны совпадать const buffer: QuestionBranchingRuleMain[] = []; - question.content.rule.main.forEach( - (condition: QuestionBranchingRuleMain) => { - buffer.forEach((oldCondition: QuestionBranchingRuleMain) => { - if (areRulesEqual(condition.rules, oldCondition.rules)) { - const currentQuestion = getQuestionByContentId(condition.next); - const oldQuestions = getQuestionByContentId(oldCondition.next); + question.content.rule.main.forEach((condition: QuestionBranchingRuleMain) => { + buffer.forEach((oldCondition: QuestionBranchingRuleMain) => { + if (areRulesEqual(condition.rules, oldCondition.rules)) { + const currentQuestion = getQuestionByContentId(condition.next); + const oldQuestions = getQuestionByContentId(oldCondition.next); - if (!currentQuestion?.type || !oldQuestions?.type) { - return; - } - - pushProblem( - question.content.id, - `У вопроса "${currentQuestion.title || "noname №" + currentQuestion.page}" и "${ - oldQuestions.title || "noname №" + oldQuestions.page - }" одинаковые условия ветвления`, - question.title, - ); + if (!currentQuestion?.type || !oldQuestions?.type) { + return; } - }); - buffer.push(condition); - }, - ); + + pushProblem( + question.content.id, + `У вопроса "${currentQuestion.title || "noname №" + currentQuestion.page}" и "${ + oldQuestions.title || "noname №" + oldQuestions.page + }" одинаковые условия ветвления`, + question.title + ); + } + }); + buffer.push(condition); + }); }); return problems; @@ -106,12 +83,7 @@ const areRulesEqual = (first: any, second: any) => { const secondArray = second[0].answers; if (firstArray.length === secondArray.length) { if (firstArray.length > 1) { - if ( - firstArray.every( - (element: any, index: number) => element === secondArray[index], - ) && - first.or === second.or - ) + if (firstArray.every((element: any, index: number) => element === secondArray[index]) && first.or === second.or) return true; } else { if (firstArray[0] === secondArray[0]) return true; diff --git a/src/utils/deleteFunc.ts b/src/utils/deleteFunc.ts index f07db4f1..3c93b4aa 100644 --- a/src/utils/deleteFunc.ts +++ b/src/utils/deleteFunc.ts @@ -1,3 +1,9 @@ +import { + AnyTypedQuizQuestion, + QuestionBranchingRule, + QuestionBranchingRuleMain, + QuizQuestionResult, +} from "@frontend/squzanswerer"; import { clearRuleForAll, createResult, @@ -9,13 +15,6 @@ import { useQuestionsStore } from "@root/questions/store"; import { updateRootContentId } from "@root/quizes/actions"; import { getCurrentQuiz } from "@root/quizes/hooks"; -import type { - AnyTypedQuizQuestion, - QuestionBranchingRule, - QuestionBranchingRuleMain, -} from "@model/questionTypes/shared"; -import { QuizQuestionResult } from "@model/questionTypes/result"; - //Всё здесь нужно сделать последовательно. И пусть весь мир ждёт. export const DeleteFunction = async (questionId: string) => { @@ -36,27 +35,16 @@ export const DeleteFunction = async (questionId: string) => { //удалить из стора вопрос из дерева и очистить его потомков const clearQuestions = [] as string[]; - const parentQuestion = getQuestionByContentId( - question.content.rule.parentId, - ); - let startCountParentChildren = parentQuestion?.type - ? parentQuestion.content.rule.children - : null; + const parentQuestion = getQuestionByContentId(question.content.rule.parentId); + let startCountParentChildren = parentQuestion?.type ? parentQuestion.content.rule.children : null; //записываем потомков , а их результаты удаляем const getChildren = (parentQuestion: AnyTypedQuizQuestion) => { questions.forEach((targetQuestion) => { - if ( - targetQuestion.type !== null && - targetQuestion.content.rule.parentId === parentQuestion.content.id - ) { + if (targetQuestion.type !== null && targetQuestion.content.rule.parentId === parentQuestion.content.id) { //если у вопроса совпал родитель с родителем => он потомок, в кучу его - if ( - targetQuestion.type !== "result" && - targetQuestion.type !== null - ) { - if (!clearQuestions.includes(targetQuestion.content.id)) - clearQuestions.push(targetQuestion.content.id); + if (targetQuestion.type !== "result" && targetQuestion.type !== null) { + if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id); getChildren(targetQuestion); //и ищем его потомков } } @@ -72,7 +60,7 @@ export const DeleteFunction = async (questionId: string) => { question.content.rule.main = []; question.content.rule.default = ""; }); - }), + }) ); if (!parentQuestion?.type) { @@ -82,18 +70,13 @@ export const DeleteFunction = async (questionId: string) => { const parentChildren = [...parentQuestion.content.rule.children]; if (parentChildren.includes(question.content.id)) - parentChildren.splice( - parentQuestion.content.rule.children.indexOf(question.content.id), - 1, - ); + parentChildren.splice(parentQuestion.content.rule.children.indexOf(question.content.id), 1); const main = parentQuestion.content.rule.main.filter( - (data: QuestionBranchingRuleMain) => data.next !== question.content.id, + (data: QuestionBranchingRuleMain) => data.next !== question.content.id ); //удаляем условия перехода от родителя к этому вопросу const defaultValue = - parentQuestion.content.rule.parentId === question.content.id - ? "" - : parentQuestion.content.rule.parentId; + parentQuestion.content.rule.parentId === question.content.id ? "" : parentQuestion.content.rule.parentId; //чистим rule родителя const newRule: QuestionBranchingRule = { @@ -109,21 +92,16 @@ export const DeleteFunction = async (questionId: string) => { await deleteQuestion(question.id); const parentResult = questions.find( - (q) => - q.type === "result" && - q.content.rule.parentId === parentQuestion.content.id, + (q) => q.type === "result" && q.content.rule.parentId === parentQuestion.content.id ); //сделать результ родителя видимым если у него не осталось потомков if (startCountParentChildren.length === 1) { if (parentResult?.type) { - await updateQuestion( - parentResult.content.id, - (item) => { - item.content.usage = true; - }, - ); + await updateQuestion(parentResult.content.id, (item) => { + item.content.usage = true; + }); } else { //почему-то не существует результа у родителя. Создаём. Новосозданные результы видны сразу await createResult(quiz.backendId, parentQuestion.content.id); @@ -133,10 +111,7 @@ export const DeleteFunction = async (questionId: string) => { await deleteQuestion(question.id); - const result = questions.find( - (q) => - q.type === "result" && q.content.rule.parentId === question.content.id, - ); + const result = questions.find((q) => q.type === "result" && q.content.rule.parentId === question.content.id); if (result) await deleteQuestion(result.id); } }; diff --git a/src/utils/deleteTimeoutedQuestions.ts b/src/utils/deleteTimeoutedQuestions.ts index b123b636..92c1cfdf 100644 --- a/src/utils/deleteTimeoutedQuestions.ts +++ b/src/utils/deleteTimeoutedQuestions.ts @@ -1,4 +1,4 @@ -import { AnyTypedQuizQuestion } from "@model/questionTypes/shared"; +import { AnyTypedQuizQuestion } from "@frontend/squzanswerer"; import { useQuestionsStore } from "@root/questions/store"; import { updateSomeWorkBackend } from "@root/uiTools/actions"; import { DeleteFunction } from "@utils/deleteFunc"; @@ -7,14 +7,12 @@ export const deleteTimeoutedQuestions = async () => { const questions = useQuestionsStore.getState().questions; const questionsForDeletion = questions.filter( - ({ type, deleted }) => type && type !== "result" && deleted, + ({ type, deleted }) => type && type !== "result" && deleted ) as AnyTypedQuizQuestion[]; if (questionsForDeletion.length > 0) { updateSomeWorkBackend(true); - await Promise.allSettled( - questionsForDeletion.map((question) => DeleteFunction(question.id)), - ); + await Promise.allSettled(questionsForDeletion.map((question) => DeleteFunction(question.id))); updateSomeWorkBackend(false); } diff --git a/src/utils/hooks/useAddAnswer.ts b/src/utils/hooks/useAddAnswer.ts index 82f8d089..fe9b2760 100644 --- a/src/utils/hooks/useAddAnswer.ts +++ b/src/utils/hooks/useAddAnswer.ts @@ -1,10 +1,7 @@ -import { useSnackbar } from "notistack"; +import { QuizQuestionsWithVariants } from "@frontend/squzanswerer"; import { addQuestionVariant } from "@root/questions/actions"; -import { QuizQuestionsWithVariants } from "@model/questionTypes/shared"; export const useAddAnswer = () => { - const { enqueueSnackbar } = useSnackbar(); - const onClickAddAnAnswer = (question: QuizQuestionsWithVariants) => { addQuestionVariant(question.id); }; diff --git a/yarn.lock b/yarn.lock index 53ecdb3a..69c78468 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1521,10 +1521,10 @@ immer "^10.0.2" reconnecting-eventsource "^1.6.2" -"@frontend/squzanswerer@^1.0.46": - version "1.0.46" - resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/43/packages/npm/@frontend/squzanswerer/-/@frontend/squzanswerer-1.0.46.tgz#15bbb575d436e16cf96d23a437390c4357e48192" - integrity sha1-Fbu1ddQ24Wz5bSOkNzkMQ1fkgZI= +"@frontend/squzanswerer@^1.0.51": + version "1.0.51" + resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/43/packages/npm/@frontend/squzanswerer/-/@frontend/squzanswerer-1.0.51.tgz#54c451750aea6ed83b28ef26a613a6addb25cc64" + integrity sha1-VMRRdQrqbtg7KO8mphOmrdslzGQ= dependencies: bowser "1.9.4" country-flag-emoji-polyfill "^0.1.8" From 7e006b759f14d5adc41e53c41628f1250012dcf5 Mon Sep 17 00:00:00 2001 From: Tamara Date: Fri, 21 Jun 2024 02:27:53 +0300 Subject: [PATCH 11/11] remove css for amo select --- src/components/CustomSelect/CustomSelect.css | 22 -------------------- src/components/CustomSelect/CustomSelect.tsx | 22 ++++++++++++++++++-- 2 files changed, 20 insertions(+), 24 deletions(-) delete mode 100644 src/components/CustomSelect/CustomSelect.css diff --git a/src/components/CustomSelect/CustomSelect.css b/src/components/CustomSelect/CustomSelect.css deleted file mode 100644 index e16e64cc..00000000 --- a/src/components/CustomSelect/CustomSelect.css +++ /dev/null @@ -1,22 +0,0 @@ -.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 index 700287c4..324b9c28 100644 --- a/src/components/CustomSelect/CustomSelect.tsx +++ b/src/components/CustomSelect/CustomSelect.tsx @@ -11,7 +11,6 @@ import { useTheme, Box, } from "@mui/material"; -import "./CustomSelect.css"; import arrow_down from "../../assets/icons/arrow_down.svg"; import { MinifiedData } from "@/pages/IntegrationsPage/IntegrationsModal/types"; @@ -174,10 +173,29 @@ export const CustomSelect: FC = ({ maxHeight: "300px", overflow: "auto", overflowX: "auto", + paddingTop: "50px", + marginTop: "-50px", + borderRadius: "28px", + }, }, }} - sx={{}} + sx={{ + display: "block", + "& .MuiSelect-select.MuiSelect-outlined.MuiInputBase-input": { + display: "none" + }, + "& .MuiSelect-icon":{ + display: "none" + }, + "& .MuiOutlinedInput-notchedOutline": { + border: 0 + }, + "& .MuiMenu-root.MuiModal-root": { + zIndex: 0 + } + + }} onChange={({ target }: SelectChangeEvent) => setSelectedItem(target.value)} onClick={toggleOpened} >