тултип для показа таймера
All checks were successful
Deploy / CreateImage (push) Successful in 3m21s
Deploy / DeployService (push) Successful in 25s

This commit is contained in:
Nastya 2025-06-15 17:20:13 +03:00
parent a7c78e57e7
commit 8604daf6a4
2 changed files with 168 additions and 88 deletions

@ -1,12 +1,11 @@
import { AuditoryItem } from "@/api/auditory";
import CopyIcon from "@/assets/icons/CopyIcon";
import Trash from "@/assets/icons/trash";
import { useCurrentQuiz } from "@/stores/quizes/hooks";
import { InfoPopover } from "@/ui_kit/InfoPopover";
import TooltipClickInfo from "@/ui_kit/Toolbars/TooltipClickInfo";
import { useDomainDefine } from "@/utils/hooks/useDomainDefine";
import { IconButton, ListItem, Skeleton, Typography, useTheme } from "@mui/material";
import { useEffect, useMemo, useState } from "react";
import { IconButton, ListItem, Typography, useTheme } from "@mui/material";
import { CopyButton } from "./CopyButton";
interface AuditoryLinkProps {
item: AuditoryItem;
@ -20,66 +19,7 @@ export const AuditoryLink = ({ utmParams, item, index, onDelete }: AuditoryLinkP
const quiz = useCurrentQuiz();
const { isTestServer } = useDomainDefine();
const getCreatedTime = (timestamp: number) => {
// Если timestamp в секундах (10 цифр)
if (timestamp.toString().length === 10) {
return new Date(timestamp * 1000).getTime();
}
// Если timestamp в миллисекундах (13 цифр)
return new Date(timestamp).getTime();
};
const [isLoading, setIsLoading] = useState(() => {
if (!item.created_at) return false;
const now = new Date().getTime();
const created = getCreatedTime(item.created_at);
const diffInMinutes = (now - created) / (1000 * 60);
console.log('Initial state:', {
created_at: item.created_at,
format: item.created_at.toString().length === 10 ? 'seconds' : 'milliseconds',
now,
created,
diffInMinutes,
isLoading: diffInMinutes < 2
});
return diffInMinutes < 2;
});
useEffect(() => {
if (!item.created_at) return;
const now = new Date().getTime();
const created = getCreatedTime(item.created_at);
const diffInMinutes = (now - created) / (1000 * 60);
console.log('Effect check:', {
created_at: item.created_at,
format: item.created_at.toString().length === 10 ? 'seconds' : 'milliseconds',
now,
created,
diffInMinutes,
timeDiff: now - created
});
if (now - created < 1000) {
console.log('Setting loading to true for new link');
setIsLoading(true);
}
if (diffInMinutes < 2) {
const timeLeft = Math.ceil((2 - diffInMinutes) * 60 * 1000);
console.log('Setting timer for:', timeLeft, 'ms');
const timer = setTimeout(() => {
console.log('Timer finished, setting loading to false');
setIsLoading(false);
}, timeLeft);
return () => clearTimeout(timer);
}
}, [item.created_at]);
const handleCopy = (text: string) => {
if (isLoading) return;
navigator.clipboard.writeText(text);
};
@ -127,32 +67,11 @@ export const AuditoryLink = ({ utmParams, item, index, onDelete }: AuditoryLinkP
<IconButton edge="end" aria-label="info" sx={{ color: theme.palette.brightPurple.main, p: 0, width: 18, height: 18 }}>
<TooltipClickInfo title={`Пол: ${item.sex === 0 ? "женский" : item.sex === 1 ? "мужской" : "оба"} \n Возраст: ${item.age}`} />
</IconButton>
{isLoading ? (
<Skeleton
variant="circular"
width={18}
height={18}
sx={{
bgcolor: theme.palette.grey[400],
marginRight: "-2px"
}}
/>
) : (
<IconButton
edge="end"
aria-label="copy"
sx={{
color: theme.palette.brightPurple.main,
p: 0,
width: 18,
height: 18,
marginRight: "-2px"
}}
onClick={() => handleCopy(linkText)}
>
<CopyIcon color={theme.palette.brightPurple.main} />
</IconButton>
)}
<CopyButton
created_at={item.created_at}
onCopy={handleCopy}
text={linkText}
/>
</>
}
>

@ -0,0 +1,161 @@
import { IconButton, Skeleton, useTheme, Tooltip, ClickAwayListener } from "@mui/material";
import { useEffect, useState } from "react";
import CopyIcon from "@/assets/icons/CopyIcon";
import { useSnackbar } from "notistack";
interface CopyButtonProps {
created_at: number;
onCopy: (text: string) => void;
text: string;
}
export const CopyButton = ({ created_at, onCopy, text }: CopyButtonProps) => {
const theme = useTheme();
const { enqueueSnackbar } = useSnackbar();
const [open, setOpen] = useState(false);
const [timeLeft, setTimeLeft] = useState<string>("");
const getCreatedTime = (timestamp: number) => {
// Если timestamp в секундах (10 цифр)
if (timestamp.toString().length === 10) {
return new Date(timestamp * 1000).getTime();
}
// Если timestamp в миллисекундах (13 цифр)
return new Date(timestamp).getTime();
};
const formatTimeLeft = (milliseconds: number) => {
const minutes = Math.floor(milliseconds / (1000 * 60));
const seconds = Math.floor((milliseconds % (1000 * 60)) / 1000);
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
};
const [isLoading, setIsLoading] = useState(() => {
if (!created_at) return false;
const now = new Date().getTime();
const created = getCreatedTime(created_at);
const diffInMinutes = (now - created) / (1000 * 60);
return diffInMinutes < 2;
});
useEffect(() => {
if (!created_at) return;
const now = new Date().getTime();
const created = getCreatedTime(created_at);
const diffInMinutes = (now - created) / (1000 * 60);
if (now - created < 1000) {
setIsLoading(true);
}
if (diffInMinutes < 2) {
const timeLeft = Math.ceil((2 - diffInMinutes) * 60 * 1000);
setTimeLeft(formatTimeLeft(timeLeft));
const timer = setInterval(() => {
const currentTime = new Date().getTime();
const elapsed = currentTime - created;
const remaining = 2 * 60 * 1000 - elapsed;
if (remaining <= 0) {
setIsLoading(false);
clearInterval(timer);
return;
}
setTimeLeft(formatTimeLeft(remaining));
}, 1000);
return () => clearInterval(timer);
}
}, [created_at]);
const handleClick = () => {
if (isLoading) return;
onCopy(text);
enqueueSnackbar("Ссылка успешно скопирована", { variant: "success" });
};
const handleTooltipClose = () => {
setOpen(false);
};
const handleTooltipOpen = () => {
setOpen(true);
};
if (isLoading) {
return (
<ClickAwayListener onClickAway={handleTooltipClose}>
<div>
<Tooltip
PopperProps={{
disablePortal: true,
sx: {
"& .MuiTooltip-tooltip": {
minWidth: "175px",
maxWidth: "175px",
whiteSpace: "normal",
textAlign: "center"
}
}
}}
placement="top"
onClose={handleTooltipClose}
open={open}
title={`Идёт процесс генерации вопросов, он будет закончен через ${timeLeft}`}
onMouseEnter={handleTooltipOpen}
onMouseLeave={handleTooltipClose}
sx={{
fontSize: "12px",
p: "10px"
}}
>
<Skeleton
variant="circular"
width={18}
height={18}
sx={{
bgcolor: theme.palette.grey[400],
marginRight: "-2px"
}}
/>
</Tooltip>
</div>
</ClickAwayListener>
);
}
return (
<IconButton
edge="end"
aria-label="copy"
sx={{
color: theme.palette.brightPurple.main,
p: 0,
width: 18,
height: 18,
marginRight: "-2px",
position: "relative",
"&:hover": {
"&::after": {
content: '""',
position: "absolute",
top: "-15px",
left: "-15px",
right: "-15px",
bottom: "-15px",
borderRadius: "50%",
backgroundColor: theme.palette.grey[500],
opacity: 0.1,
zIndex: -1
}
}
}}
onClick={handleClick}
>
<CopyIcon color={theme.palette.brightPurple.main} />
</IconButton>
);
};