add popup quiz features
This commit is contained in:
parent
7749b00e56
commit
cd972e493b
@ -1,20 +1,19 @@
|
|||||||
import lightTheme from "@/utils/themes/light";
|
import lightTheme from "@/utils/themes/light";
|
||||||
import { Box, ThemeProvider, Typography } from "@mui/material";
|
import { Box, ThemeProvider, Typography } from "@mui/material";
|
||||||
import { useEffect, useRef } from "react";
|
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",
|
quizId: "3c49550d-8c77-4788-bc2d-42586a261514",
|
||||||
position: "right",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function WidgetDev() {
|
export default function WidgetDev() {
|
||||||
const widgetRef = useRef<SideWidget | null>(null);
|
const widgetRef = useRef<Widget | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!widgetRef.current) {
|
if (!widgetRef.current) {
|
||||||
widgetRef.current = new SideWidget(widgetProps);
|
widgetRef.current = new Widget(widgetProps);
|
||||||
} else {
|
} else {
|
||||||
widgetRef.current.render(widgetProps);
|
widgetRef.current.render(widgetProps);
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,25 @@
|
|||||||
import { Root, createRoot } from "react-dom/client";
|
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 {
|
export class PopupWidget {
|
||||||
root: Root | undefined;
|
root: Root | undefined;
|
||||||
element: HTMLDivElement;
|
element = document.createElement("div");
|
||||||
|
|
||||||
constructor({ quizId }: {
|
constructor(props: Props) {
|
||||||
quizId: string;
|
|
||||||
}) {
|
|
||||||
this.element = document.createElement("div");
|
|
||||||
this.element.style.setProperty("display", "none");
|
this.element.style.setProperty("display", "none");
|
||||||
document.body.appendChild(this.element);
|
document.body.appendChild(this.element);
|
||||||
|
|
||||||
this.root = createRoot(this.element);
|
this.root = createRoot(this.element);
|
||||||
|
|
||||||
this.root.render(
|
this.render(props);
|
||||||
<QuizDialog
|
}
|
||||||
quizId={quizId}
|
|
||||||
onClose={() => this.destroy()}
|
render(props: Props) {
|
||||||
/>
|
this.root?.render(<QuizPopup {...props} />);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
|
78
src/widgets/popup/QuizPopup.tsx
Normal file
78
src/widgets/popup/QuizPopup.tsx
Normal file
@ -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",
|
backgroundColor: "transparent",
|
||||||
width: "calc(min(100%, max(70%, 700px)))",
|
width: "calc(min(100%, max(70%, 700px)))",
|
||||||
height: "80%",
|
|
||||||
maxWidth: "100%",
|
maxWidth: "100%",
|
||||||
|
height: "80%",
|
||||||
|
maxHeight: "100%",
|
||||||
m: "16px",
|
m: "16px",
|
||||||
},
|
},
|
||||||
...(Array.isArray(paperSx) ? paperSx : [paperSx])
|
...(Array.isArray(paperSx) ? paperSx : [paperSx])
|
||||||
|
Loading…
Reference in New Issue
Block a user