w-aura/src/components/BreathPage/index.tsx
Daniil Chemerkin 000f28190b Develop
2024-04-02 22:03:16 +00:00

174 lines
5.2 KiB
TypeScript

import styles from "./styles.module.css";
import { useCallback, useEffect, useRef, useState } from "react";
import { UserCallbacks, useApi, useApiCall } from "@/api";
import { useDispatch, useSelector } from "react-redux";
import { actions, selectors } from "@/store";
import { useTranslation } from "react-i18next";
import FullScreenModal from "../FullScreenModal";
import StartBreathModalChild from "../StartBreathModalChild";
import Title from "../Title";
import { useNavigate } from "react-router-dom";
import routes from "@/routes";
import { APNG } from "apng-js";
import Player from "apng-js/types/library/player";
let apngPlayer: Player | null = null;
interface BreathPageProps {
leoApng: Error | APNG;
}
function BreathPage({ leoApng }: BreathPageProps): JSX.Element {
const { t } = useTranslation();
const [isOpenModal, setIsOpenModal] = useState<boolean>(true);
const [isShowPreview, setIsShowPreview] = useState<boolean>(true);
const leoCanvasRef = useRef<HTMLCanvasElement>(null);
const pageRef = useRef<HTMLElement>(null);
const api = useApi();
const dispatch = useDispatch();
const navigate = useNavigate();
const homeConfig = useSelector(selectors.selectHome);
const showNavbarFooter = homeConfig.isShowNavbar;
const queryTimeOutRef = useRef<NodeJS.Timeout>();
useEffect(() => {
return () => {
if (queryTimeOutRef.current) {
clearTimeout(queryTimeOutRef.current);
}
};
}, []);
useEffect(() => {
if (isOpenModal) return;
const previewTimeOut = setTimeout(() => {
setIsShowPreview(false);
apngPlayer?.play();
}, 10_000);
const navigateTimeOut = setTimeout(() => {
navigate(routes.client.breathResult());
}, 50_000);
return () => {
clearTimeout(navigateTimeOut);
clearTimeout(previewTimeOut);
};
}, [navigate, isOpenModal]);
useEffect(() => {
async function getApngPlayer() {
const context = leoCanvasRef.current?.getContext("2d");
if (context && !(leoApng instanceof Error)) {
context.canvas.height = leoApng.height;
context.canvas.width = leoApng.width;
const _apngPlayer = await leoApng.getPlayer(context);
apngPlayer = _apngPlayer;
if (apngPlayer) {
apngPlayer.stop();
}
}
}
getApngPlayer();
}, [leoApng]);
const beginBreath = () => {
setIsOpenModal(false);
};
const token = useSelector(selectors.selectToken);
const createCallback = useCallback(async () => {
const data: UserCallbacks.PayloadPost = {
data: {
user_callback: {
kind: "breathing_end",
},
},
token,
};
const createCallbackRequest = await api.createUserCallbacks(data);
dispatch(actions.userCallbacks.update(createCallbackRequest.user_callback));
if (!createCallbackRequest.user_callback.is_complete) {
const getUserCallbacksRequest = async () => {
const getCallback = await api.getUserCallbacks({
id: createCallbackRequest.user_callback.id,
token,
});
if (!getCallback.user_callback.is_complete) {
queryTimeOutRef.current = setTimeout(getUserCallbacksRequest, 3000);
}
dispatch(
actions.userCallbacks.update({
description: getCallback.user_callback.description || "Loading...",
})
);
return getCallback.user_callback;
};
return await getUserCallbacksRequest();
}
return createCallbackRequest.user_callback;
}, [api, dispatch, token]);
useApiCall<UserCallbacks.IUserCallbacks>(createCallback);
const handleCross = () => {
navigate(routes.client.breathResult());
};
return (
<>
<section
className={`${styles.page} page`}
ref={pageRef}
style={{ paddingBottom: showNavbarFooter ? "48px" : "16px" }}
>
{!showNavbarFooter && (
<div className={styles.cross} onClick={handleCross}></div>
)}
<canvas
style={{ display: isOpenModal ? "hidden" : "block" }}
className={`${styles["leo-apng"]} ${
!isOpenModal && isShowPreview ? styles.leo : ""
}`}
ref={leoCanvasRef}
></canvas>
{!isOpenModal && isShowPreview && (
<div className={styles.preview}>
<Title
variant="h2"
className={`${styles.text} ${styles["breath-relax"]}`}
>
{t("aura.breath_relax.text")}
</Title>
</div>
)}
<FullScreenModal isOpen={isOpenModal}>
<StartBreathModalChild
handleBegin={beginBreath}
isShowNavbar={showNavbarFooter}
/>
</FullScreenModal>
{!isOpenModal && !isShowPreview && (
<div className={styles["text-container"]}>
<Title
variant="h2"
className={`${styles.text} ${styles["breath-in"]}`}
>
{t("breathIn")}
</Title>
<Title
variant="h2"
className={`${styles.text} ${styles["breath-out"]}`}
>
{t("breathOut")}
</Title>
</div>
)}
</section>
</>
);
}
export default BreathPage;