164 lines
5.3 KiB
TypeScript
164 lines
5.3 KiB
TypeScript
import styles from "./styles.module.css";
|
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
import { UserCallbacks, useApi, useApiCall } from "@/api";
|
|
import { Asset } from "@/api/resources/Assets";
|
|
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 parseAPNG from "apng-js";
|
|
import Player from "apng-js/types/library/player";
|
|
|
|
let apngPlayer: Player | null = null;
|
|
|
|
function BreathPage(): 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 assetsData = useCallback(async () => {
|
|
const { assets } = await api.getAssets({
|
|
category: String("au"),
|
|
});
|
|
return assets;
|
|
}, [api]);
|
|
|
|
const { data } = useApiCall<Asset[]>(assetsData);
|
|
|
|
useEffect(() => {
|
|
if (isOpenModal) return;
|
|
const previewTimeOut = setTimeout(() => {
|
|
setIsShowPreview(false);
|
|
apngPlayer?.play();
|
|
}, 10_000);
|
|
|
|
const navigateTimeOut = setTimeout(() => {
|
|
navigate(routes.client.breathResult());
|
|
}, 60_000);
|
|
|
|
return () => {
|
|
clearTimeout(navigateTimeOut);
|
|
clearTimeout(previewTimeOut);
|
|
};
|
|
}, [navigate, isOpenModal]);
|
|
|
|
useEffect(() => {
|
|
async function getApng() {
|
|
if (!data) return;
|
|
const response = await fetch(
|
|
data.find((item) => item.key === "au.apng.leo")?.url || ""
|
|
);
|
|
const arrayBuffer = await response.arrayBuffer();
|
|
const apng = parseAPNG(arrayBuffer);
|
|
const context = leoCanvasRef.current?.getContext("2d");
|
|
if (context && !(apng instanceof Error)) {
|
|
context.canvas.height = apng.height;
|
|
context.canvas.width = apng.width;
|
|
const _apngPlayer = await apng.getPlayer(context);
|
|
apngPlayer = _apngPlayer;
|
|
if (apngPlayer) {
|
|
apngPlayer.stop();
|
|
}
|
|
}
|
|
}
|
|
getApng();
|
|
}, [data]);
|
|
|
|
const beginBreath = () => {
|
|
setIsOpenModal(false);
|
|
};
|
|
|
|
const token =
|
|
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIzNjEyLCJpYXQiOjE2OTM0MTg5MTAsImV4cCI6MTcwMjA1ODkxMCwianRpIjoiNzg5MjkwYWItODg0YS00MGUyLTkyNjEtOWI2OGEyNjkwNmE0IiwiZW1haWwiOiJvdGhlckBleGFtcGxlLmNvbSIsInN0YXRlIjoicHJvdmVuIiwibG9jIjoiZW4iLCJ0eiI6LTI4ODAwLCJ0eXBlIjoiZW1haWwiLCJpc3MiOiJjb20ubGlmZS5hdXJhIn0.J2ocWIv5jKzuKMcwMgWMiNMyGg5qLlMAeln-bQm_9lw";
|
|
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) {
|
|
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]);
|
|
|
|
useApiCall<UserCallbacks.IUserCallbacks>(createCallback);
|
|
|
|
return (
|
|
<>
|
|
<section className={`${styles.page} page`} ref={pageRef} style={{ paddingBottom: showNavbarFooter ? '48px' : '16px'}}>
|
|
<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} />
|
|
</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;
|