w-aura/src/components/BreathPage/index.tsx

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;