214 lines
5.6 KiB
TypeScript
214 lines
5.6 KiB
TypeScript
|
|
import { Box, Typography, useTheme, SxProps, Theme } from "@mui/material";
|
|||
|
|
import { useQuizStore } from "@stores/useQuizStore";
|
|||
|
|
import moment from "moment";
|
|||
|
|
import React from "react";
|
|||
|
|
import { useTranslation } from "react-i18next";
|
|||
|
|
|
|||
|
|
type OverTimeProps = {
|
|||
|
|
sx?: SxProps<Theme>;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export const OverTime = ({ sx }: OverTimeProps) => {
|
|||
|
|
const theme = useTheme();
|
|||
|
|
const { settings } = useQuizStore();
|
|||
|
|
const { t } = useTranslation();
|
|||
|
|
const [currentTime, setCurrentTime] = React.useState(moment());
|
|||
|
|
|
|||
|
|
// Реактивный таймер с useEffect
|
|||
|
|
React.useEffect(() => {
|
|||
|
|
const interval = setInterval(() => {
|
|||
|
|
setCurrentTime(moment());
|
|||
|
|
}, 1000);
|
|||
|
|
|
|||
|
|
return () => clearInterval(interval);
|
|||
|
|
}, []);
|
|||
|
|
|
|||
|
|
// Проверяем, включен ли overTime
|
|||
|
|
const overTimeConfig = settings?.cfg?.overTime;
|
|||
|
|
const isEnabled = overTimeConfig?.enabled;
|
|||
|
|
|
|||
|
|
// Если не включен, не показываем карточку
|
|||
|
|
if (!isEnabled) {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Функция для расчета времени до окончания
|
|||
|
|
const calculateTimeLeft = (now: moment.Moment) => {
|
|||
|
|
// Для тестирования: добавляем 2 часа к текущему времени
|
|||
|
|
const testEndsAt = moment().add(2, "hours");
|
|||
|
|
const endsAt = overTimeConfig?.endsAt ? moment(overTimeConfig.endsAt) : testEndsAt;
|
|||
|
|
|
|||
|
|
if (endsAt.isBefore(now) || endsAt.isSame(now)) {
|
|||
|
|
return { days: 0, hours: 0, minutes: 0, seconds: 0 };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const duration = moment.duration(endsAt.diff(now));
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
days: Math.floor(duration.asDays()),
|
|||
|
|
hours: duration.hours(),
|
|||
|
|
minutes: duration.minutes(),
|
|||
|
|
seconds: duration.seconds(),
|
|||
|
|
};
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const { days, hours, minutes, seconds } = calculateTimeLeft(currentTime);
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<Box
|
|||
|
|
sx={{
|
|||
|
|
width: "225px",
|
|||
|
|
backgroundColor: (theme.palette as any).paperBackground,
|
|||
|
|
boxShadow: "1px 1px 4px 0px rgba(51, 54, 71, 0.29)",
|
|||
|
|
borderRadius: "8px",
|
|||
|
|
p: "10px",
|
|||
|
|
...sx,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
<Typography
|
|||
|
|
sx={{
|
|||
|
|
fontSize: "12px",
|
|||
|
|
color: (theme.palette as any).paperText,
|
|||
|
|
textAlign: "center",
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
{overTimeConfig?.description || t("Quiz will become unavailable in")}
|
|||
|
|
</Typography>
|
|||
|
|
<Box
|
|||
|
|
sx={{
|
|||
|
|
display: "inline-flex",
|
|||
|
|
justifyContent: "space-around",
|
|||
|
|
alignItems: "center",
|
|||
|
|
width: "100%",
|
|||
|
|
mt: "8px",
|
|||
|
|
color: (theme.palette as any).paperSecondaryText,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
<Box
|
|||
|
|
sx={{
|
|||
|
|
bgcolor: (theme.palette as any).paperBlockBackground,
|
|||
|
|
width: "42px",
|
|||
|
|
height: "45px",
|
|||
|
|
display: "flex",
|
|||
|
|
flexDirection: "column",
|
|||
|
|
alignItems: "center",
|
|||
|
|
borderRadius: "8px",
|
|||
|
|
justifyContent: "center",
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
<Typography
|
|||
|
|
sx={{
|
|||
|
|
fontSize: "16px",
|
|||
|
|
color: (theme.palette as any).paperText,
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
{days}
|
|||
|
|
</Typography>
|
|||
|
|
<Typography
|
|||
|
|
sx={{
|
|||
|
|
fontSize: "10px",
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
{t("days")}
|
|||
|
|
</Typography>
|
|||
|
|
</Box>
|
|||
|
|
:
|
|||
|
|
<Box
|
|||
|
|
sx={{
|
|||
|
|
bgcolor: (theme.palette as any).paperBlockBackground,
|
|||
|
|
width: "42px",
|
|||
|
|
height: "45px",
|
|||
|
|
display: "flex",
|
|||
|
|
flexDirection: "column",
|
|||
|
|
alignItems: "center",
|
|||
|
|
borderRadius: "8px",
|
|||
|
|
justifyContent: "center",
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
<Typography
|
|||
|
|
sx={{
|
|||
|
|
fontSize: "16px",
|
|||
|
|
color: (theme.palette as any).paperText,
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
{hours}
|
|||
|
|
</Typography>
|
|||
|
|
<Typography
|
|||
|
|
sx={{
|
|||
|
|
fontSize: "10px",
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
{t("hours")}
|
|||
|
|
</Typography>
|
|||
|
|
</Box>
|
|||
|
|
:
|
|||
|
|
<Box
|
|||
|
|
sx={{
|
|||
|
|
bgcolor: (theme.palette as any).paperBlockBackground,
|
|||
|
|
width: "42px",
|
|||
|
|
height: "45px",
|
|||
|
|
display: "flex",
|
|||
|
|
flexDirection: "column",
|
|||
|
|
alignItems: "center",
|
|||
|
|
borderRadius: "8px",
|
|||
|
|
justifyContent: "center",
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
<Typography
|
|||
|
|
sx={{
|
|||
|
|
fontSize: "16px",
|
|||
|
|
color: (theme.palette as any).paperText,
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
{minutes}
|
|||
|
|
</Typography>
|
|||
|
|
<Typography
|
|||
|
|
sx={{
|
|||
|
|
fontSize: "10px",
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
{t("minutes")}
|
|||
|
|
</Typography>
|
|||
|
|
</Box>
|
|||
|
|
:
|
|||
|
|
<Box
|
|||
|
|
sx={{
|
|||
|
|
bgcolor: (theme.palette as any).paperBlockBackground,
|
|||
|
|
width: "42px",
|
|||
|
|
height: "45px",
|
|||
|
|
display: "flex",
|
|||
|
|
flexDirection: "column",
|
|||
|
|
alignItems: "center",
|
|||
|
|
borderRadius: "8px",
|
|||
|
|
justifyContent: "center",
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
<Typography
|
|||
|
|
sx={{
|
|||
|
|
fontSize: "16px",
|
|||
|
|
color: (theme.palette as any).paperText,
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
{seconds}
|
|||
|
|
</Typography>
|
|||
|
|
<Typography
|
|||
|
|
sx={{
|
|||
|
|
fontSize: "10px",
|
|||
|
|
lineHeight: 1.2,
|
|||
|
|
}}
|
|||
|
|
>
|
|||
|
|
{t("seconds")}
|
|||
|
|
</Typography>
|
|||
|
|
</Box>
|
|||
|
|
</Box>
|
|||
|
|
</Box>
|
|||
|
|
);
|
|||
|
|
};
|