Merge branch 'dev' into 'staging'

Dev

See merge request frontend/squiz!346
This commit is contained in:
Nastya 2024-06-24 16:45:46 +00:00
commit bae93b1bf1
6 changed files with 182 additions and 39 deletions

@ -1,6 +1,7 @@
import { QuestionKeys } from "@/pages/IntegrationsPage/IntegrationsModal/types"; import { QuestionKeys } from "@/pages/IntegrationsPage/IntegrationsModal/types";
import { makeRequest } from "@api/makeRequest"; import { makeRequest } from "@api/makeRequest";
import { parseAxiosError } from "@utils/parse-error"; import { parseAxiosError } from "@utils/parse-error";
import useSWR from "swr";
export type PaginationRequest = { export type PaginationRequest = {
page: number; page: number;
@ -21,6 +22,7 @@ export type AccountResponse = {
subdomain: string; subdomain: string;
country: string; country: string;
driveURL: string; driveURL: string;
stale: boolean;
}; };
export const getAccount = async (): Promise<[AccountResponse | null, string?]> => { export const getAccount = async (): Promise<[AccountResponse | null, string?]> => {
@ -37,6 +39,16 @@ export const getAccount = async (): Promise<[AccountResponse | null, string?]> =
} }
}; };
export function useAmoAccount() {
return useSWR("amoAccount", () =>
makeRequest<void, AccountResponse>({
method: "GET",
url: `${API_URL}/account`,
useToken: true,
})
);
}
// подключить Amo // подключить Amo
export const connectAmo = async (): Promise<[string | null, string?]> => { export const connectAmo = async (): Promise<[string | null, string?]> => {

@ -44,6 +44,7 @@ export const AmoAccountInfo: FC<AmoAccountInfoProps> = ({ handleNextStep, accoun
<a <a
target="_blank" target="_blank"
href={link} href={link}
style={{wordBreak: "break-word"}}
> >
{link} {link}
</a> </a>

@ -1,5 +1,5 @@
import React, { FC, useCallback, useEffect, useMemo, useState } from "react"; import React, { FC, useCallback, useEffect, useMemo, useState } from "react";
import { Dialog, IconButton, Typography, useMediaQuery, useTheme, Box } from "@mui/material"; import {Dialog, IconButton, Typography, useMediaQuery, useTheme, Box, Skeleton} from "@mui/material";
import { useQuestions } from "@/stores/questions/hooks"; import { useQuestions } from "@/stores/questions/hooks";
import { redirect } from "react-router-dom"; import { redirect } from "react-router-dom";
import { enqueueSnackbar } from "notistack"; import { enqueueSnackbar } from "notistack";
@ -73,7 +73,7 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({ isModalOpen, handleClo
const [openDelete, setOpenDelete] = useState<TagQuestionHC | null>(null); const [openDelete, setOpenDelete] = useState<TagQuestionHC | null>(null);
const { const {
isloadingPage, isLoadingPage,
firstRules, firstRules,
accountInfo, accountInfo,
arrayOfPipelines, arrayOfPipelines,
@ -360,43 +360,56 @@ export const AmoCRMModal: FC<IntegrationsModalProps> = ({ isModalOpen, handleClo
flexGrow: 1, flexGrow: 1,
}} }}
> >
<AmoModalTitle {isLoadingPage ?
step={step} <Skeleton
steps={steps} sx={{
isSettingsBlock={isSettingsBlock} width: "100%",
setIsSettingsBlock={setIsSettingsBlock} height: "100%",
setStep={setStep} transform: "none",
startRemoveAccount={() => setIsTryRemoveAccount(true)} }}
/> /> :
{openDelete !== null ? ( <>
<AmoDeleteTagQuestion <AmoModalTitle
close={() => setOpenDelete(null)} step={step}
deleteItem={handleDeleteTagQuestion} steps={steps}
/> isSettingsBlock={isSettingsBlock}
) : (
<>
{isTryRemoveAccount && <AmoRemoveAccount stopThisPage={() => setIsTryRemoveAccount(false)} />}
{isSettingsBlock && (
<Box sx={{ flexGrow: 1, width: "100%" }}>
<AmoSettingsBlock
stepTitles={stepTitles}
setIsSettingsBlock={setIsSettingsBlock} setIsSettingsBlock={setIsSettingsBlock}
setStep={setStep} setStep={setStep}
selectedDealUser={arrayOfUsers.find((u) => u.id === selectedDealUser)?.title || "не указан"} startRemoveAccount={() => setIsTryRemoveAccount(true)}
selectedFunnel={arrayOfPipelines.find((p) => p.id === selectedPipeline)?.title || "нет данных"} />
selectedStage={ {openDelete !== null ? (
arrayOfPipelinesSteps.find((s) => s.id === selectedPipelineStep)?.title || "нет данных" <AmoDeleteTagQuestion
} close={() => setOpenDelete(null)}
selectedQuestions={selectedQuestions} deleteItem={handleDeleteTagQuestion}
selectedTags={selectedTags} />
/> ) : (
</Box> <>
)} {isTryRemoveAccount && <AmoRemoveAccount stopThisPage={() => setIsTryRemoveAccount(false)} />}
{!isSettingsBlock && !isTryRemoveAccount && ( {isSettingsBlock && (
<Box sx={{ flexGrow: 1, width: "100%" }}>{steps[step].component}</Box> <Box sx={{ flexGrow: 1, width: "100%" }}>
)} <AmoSettingsBlock
</> stepTitles={stepTitles}
)} setIsSettingsBlock={setIsSettingsBlock}
setStep={setStep}
selectedDealUser={arrayOfUsers.find((u) => u.id === selectedDealUser)?.title || "не указан"}
selectedFunnel={arrayOfPipelines.find((p) => p.id === selectedPipeline)?.title || "нет данных"}
selectedStage={
arrayOfPipelinesSteps.find((s) => s.id === selectedPipelineStep)?.title || "нет данных"
}
selectedQuestions={selectedQuestions}
selectedTags={selectedTags}
/>
</Box>
)}
{!isSettingsBlock && !isTryRemoveAccount && (
<Box sx={{ flexGrow: 1, width: "100%" }}>{steps[step].component}</Box>
)}
</>
)}
</>
}
</Box> </Box>
</Dialog> </Dialog>
); );

@ -0,0 +1,113 @@
import { connectAmo } from "@/api/integration";
import CustomCheckbox from "@/ui_kit/CustomCheckbox";
import { Box, Button, Dialog, Typography, useMediaQuery, useTheme } from "@mui/material";
import { useState } from "react";
const HIDE_DIALOG_EXPIRATION_PERIOD = 24 * 60 * 60 * 1000;
interface Props {
initialOpen: boolean;
}
export default function AmoTokenExpiredDialog({ initialOpen }: Props) {
const theme = useTheme();
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(() => {
const hideExpirationTime = Number(localStorage.getItem("hideAmoTokenExpiredDialogExpirationTime"));
if (hideExpirationTime && hideExpirationTime > Date.now()) return false;
return initialOpen;
});
const [isHideDialogForADayChecked, setIsHideDialogForADayChecked] = useState<boolean>(false);
const onAmoClick = async () => {
const [url, error] = await connectAmo();
if (url && !error) {
window.open(url, "_blank");
}
};
function handleDialogClose() {
if (isHideDialogForADayChecked) {
const expirationDate = Date.now() + HIDE_DIALOG_EXPIRATION_PERIOD;
localStorage.setItem("hideAmoTokenExpiredDialogExpirationTime", expirationDate.toString());
}
setIsDialogOpen(false);
}
return (
<Dialog
open={isDialogOpen}
onClose={handleDialogClose}
PaperProps={{
sx: {
borderRadius: "12px",
maxWidth: "620px",
},
}}
>
<Box
sx={{
p: "20px",
backgroundColor: "#F2F3F7",
}}
>
<Typography
color="#4D4D4D"
fontSize="24px"
fontWeight="medium"
>
Ваш amo-токен не работает
</Typography>
</Box>
<Box
sx={{
p: "20px",
display: "flex",
flexDirection: "column",
gap: "30px",
}}
>
<Typography color="#4D4D4D">
Amo отозвал ваш токен. Зайдите заново в свой аккаунт, чтобы вам снова начали приходить сделки.
</Typography>
<Box
sx={{
display: "flex",
gap: "10px",
[theme.breakpoints.down("sm")]: {
flexDirection: "column-reverse",
},
}}
>
<Button
variant="outlined"
onClick={handleDialogClose}
sx={{
flex: "1 0 0",
borderColor: "#9A9AAF",
}}
>
Позже
</Button>
<Button
variant="contained"
onClick={onAmoClick}
sx={{
flex: "1 0 0",
}}
>
Перелогиниться
</Button>
</Box>
<CustomCheckbox
label={"Не показывать сутки"}
checked={isHideDialogForADayChecked}
handleChange={({ target }) => {
setIsHideDialogForADayChecked(target.checked);
}}
/>
</Box>
</Dialog>
);
}

@ -21,7 +21,7 @@ interface Props {
} }
export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID }: Props) => { export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID }: Props) => {
const [isloadingPage, setIsLoadingPage] = useState<boolean>(true); const [isLoadingPage, setIsLoadingPage] = useState<boolean>(true);
const [firstRules, setFirstRules] = useState<boolean>(false); const [firstRules, setFirstRules] = useState<boolean>(false);
const [accountInfo, setAccountInfo] = useState<AccountResponse | null>(null); const [accountInfo, setAccountInfo] = useState<AccountResponse | null>(null);
@ -224,7 +224,7 @@ export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID }: P
}, [pageOfTags]); }, [pageOfTags]);
return { return {
isloadingPage, isLoadingPage,
firstRules, firstRules,
accountInfo, accountInfo,
arrayOfPipelines, arrayOfPipelines,

@ -21,6 +21,8 @@ import { AnyTypedQuizQuestion } from "@frontend/squzanswerer";
import { ModalInfoWhyCantCreate } from "./ModalInfoWhyCantCreate"; import { ModalInfoWhyCantCreate } from "./ModalInfoWhyCantCreate";
import { ConfirmLeaveModal } from "./ConfirmLeaveModal"; import { ConfirmLeaveModal } from "./ConfirmLeaveModal";
import { checkQuestionHint } from "@utils/checkQuestionHint"; import { checkQuestionHint } from "@utils/checkQuestionHint";
import AmoTokenExpiredDialog from "../IntegrationsPage/IntegrationsModal/AmoTokenExpiredDialog";
import { useAmoAccount } from "@/api/integration";
interface Props { interface Props {
openBranchingPage: boolean; openBranchingPage: boolean;
@ -41,6 +43,7 @@ export default function EditPage({
setScrollDown, setScrollDown,
}: Props) { }: Props) {
const quiz = useCurrentQuiz(); const quiz = useCurrentQuiz();
const { data: amoAccount } = useAmoAccount();
const { editQuizId } = useQuizStore(); const { editQuizId } = useQuizStore();
const { questions } = useQuestionsStore(); const { questions } = useQuestionsStore();
const { showConfirmLeaveModal, nextStep } = useUiTools(); const { showConfirmLeaveModal, nextStep } = useUiTools();
@ -105,6 +108,7 @@ export default function EditPage({
return ( return (
<> <>
{amoAccount && <AmoTokenExpiredDialog initialOpen={amoAccount.stale} />}
<Box <Box
sx={{ sx={{
display: isMobile ? "block" : "flex", display: isMobile ? "block" : "flex",