add popup quiz features

This commit is contained in:
nflnkr 2024-05-08 20:50:18 +03:00
parent 7749b00e56
commit cd972e493b
4 changed files with 95 additions and 18 deletions

@ -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<typeof SideWidget>[0] = {
const widgetProps: ConstructorParameters<typeof Widget>[0] = {
quizId: "3c49550d-8c77-4788-bc2d-42586a261514",
position: "right",
};
export default function WidgetDev() {
const widgetRef = useRef<SideWidget | null>(null);
const widgetRef = useRef<Widget | null>(null);
useEffect(() => {
if (!widgetRef.current) {
widgetRef.current = new SideWidget(widgetProps);
widgetRef.current = new Widget(widgetProps);
} else {
widgetRef.current.render(widgetProps);
}

@ -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<typeof QuizPopup>;
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(
<QuizDialog
quizId={quizId}
onClose={() => this.destroy()}
/>
);
this.render(props);
}
render(props: Props) {
this.root?.render(<QuizPopup {...props} />);
}
destroy() {

@ -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<boolean>(initialIsQuizShown);
const isQuizCompleted = useQuizCompletionStatus(quizId);
const isMobile = useMediaQuery("(max-width: 600px)");
const preventOpenOnLeaveAttemptRef = useRef<boolean>(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 (
<QuizDialog
open={isQuizShown}
quizId={quizId}
onClose={() => setIsQuizShown(false)}
paperSx={{
width: dimensions?.width ?? WIDGET_DEFAULT_WIDTH,
height: dimensions?.height ?? WIDGET_DEFAULT_HEIGHT,
}}
/>
);
}

@ -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])