diff --git a/src/WidgetDev.tsx b/src/WidgetDev.tsx index 9159934..901713c 100644 --- a/src/WidgetDev.tsx +++ b/src/WidgetDev.tsx @@ -1,20 +1,19 @@ import lightTheme from "@/utils/themes/light"; import { Box, ThemeProvider, Typography } from "@mui/material"; import { useEffect, useRef } from "react"; -import { SideWidget } from "./widgets"; +import { PopupWidget as Widget } from "./widgets"; -const widgetProps: ConstructorParameters[0] = { +const widgetProps: ConstructorParameters[0] = { quizId: "3c49550d-8c77-4788-bc2d-42586a261514", - position: "right", }; export default function WidgetDev() { - const widgetRef = useRef(null); + const widgetRef = useRef(null); useEffect(() => { if (!widgetRef.current) { - widgetRef.current = new SideWidget(widgetProps); + widgetRef.current = new Widget(widgetProps); } else { widgetRef.current.render(widgetProps); } diff --git a/src/widgets/popup/PopupWidget.tsx b/src/widgets/popup/PopupWidget.tsx index eb490bd..d238eaa 100644 --- a/src/widgets/popup/PopupWidget.tsx +++ b/src/widgets/popup/PopupWidget.tsx @@ -1,26 +1,25 @@ import { Root, createRoot } from "react-dom/client"; -import QuizDialog from "../shared/QuizDialog"; +import { ComponentPropsWithoutRef } from "react"; +import QuizPopup from "./QuizPopup"; +type Props = ComponentPropsWithoutRef; + export class PopupWidget { root: Root | undefined; - element: HTMLDivElement; + element = document.createElement("div"); - constructor({ quizId }: { - quizId: string; - }) { - this.element = document.createElement("div"); + constructor(props: Props) { this.element.style.setProperty("display", "none"); document.body.appendChild(this.element); this.root = createRoot(this.element); - this.root.render( - this.destroy()} - /> - ); + this.render(props); + } + + render(props: Props) { + this.root?.render(); } destroy() { diff --git a/src/widgets/popup/QuizPopup.tsx b/src/widgets/popup/QuizPopup.tsx new file mode 100644 index 0000000..f824328 --- /dev/null +++ b/src/widgets/popup/QuizPopup.tsx @@ -0,0 +1,78 @@ +import { useEffect, useRef, useState } from "react"; +import QuizDialog from "../shared/QuizDialog"; +import { useQuizCompletionStatus } from "../shared/useQuizCompletionStatus"; +import { useMediaQuery } from "@mui/material"; + + +const WIDGET_DEFAULT_WIDTH = "600px"; +const WIDGET_DEFAULT_HEIGHT = "80%"; + +interface Props { + quizId: string; + dimensions?: { width: string; height: string; }; + /** + * Открыть квиз через X секунд + */ + autoShowQuizTime?: number; + hideOnMobile?: boolean; + openOnLeaveAttempt?: boolean; +} + +export default function QuizPopup({ + quizId, + dimensions, + autoShowQuizTime = 0, + hideOnMobile = false, + openOnLeaveAttempt = false, +}: Props) { + const initialIsQuizShown = (autoShowQuizTime || openOnLeaveAttempt) ? false : true; + + const [isQuizShown, setIsQuizShown] = useState(initialIsQuizShown); + const isQuizCompleted = useQuizCompletionStatus(quizId); + const isMobile = useMediaQuery("(max-width: 600px)"); + const preventOpenOnLeaveAttemptRef = useRef(false); + + useEffect(function setAutoShowQuizTimer() { + if (!autoShowQuizTime || openOnLeaveAttempt) return; + + const timeout = setTimeout(() => { + setIsQuizShown(true); + }, autoShowQuizTime * 1000); + + return () => { + clearTimeout(timeout); + }; + }, [autoShowQuizTime, openOnLeaveAttempt]); + + useEffect(function attachLeaveListener() { + if (!openOnLeaveAttempt) return; + + const handleMouseLeave = () => { + if (!preventOpenOnLeaveAttemptRef.current) { + preventOpenOnLeaveAttemptRef.current = true; + setIsQuizShown(true); + } + }; + + document.addEventListener("mouseleave", handleMouseLeave); + + return () => { + document.removeEventListener("mouseleave", handleMouseLeave); + }; + }, [openOnLeaveAttempt]); + + if (isQuizCompleted) return null; + if (hideOnMobile && isMobile) return null; + + return ( + setIsQuizShown(false)} + paperSx={{ + width: dimensions?.width ?? WIDGET_DEFAULT_WIDTH, + height: dimensions?.height ?? WIDGET_DEFAULT_HEIGHT, + }} + /> + ); +} diff --git a/src/widgets/shared/QuizDialog.tsx b/src/widgets/shared/QuizDialog.tsx index 4429a3a..fa3895c 100644 --- a/src/widgets/shared/QuizDialog.tsx +++ b/src/widgets/shared/QuizDialog.tsx @@ -41,8 +41,9 @@ export default function QuizDialog({ { backgroundColor: "transparent", width: "calc(min(100%, max(70%, 700px)))", - height: "80%", maxWidth: "100%", + height: "80%", + maxHeight: "100%", m: "16px", }, ...(Array.isArray(paperSx) ? paperSx : [paperSx])