import { Star, StarOff } from "lucide-react" import { memo, useCallback, useEffect, useRef, useState } from "react" import { useTranslation } from "react-i18next" import { useFavorites } from "@/features/app-state" import { shortcutsRegistry } from "@/features/keyboard-shortcuts" import { MediaFile } from "@/features/media/types/media" import { cn } from "@/lib/utils" interface FavoriteButtonProps { file: MediaFile size?: number type?: "media" | "music" | "transition" | "effect" | "template" | "filter" | "subtitle" | "styleTemplate" } /** * Кнопка для добавления/удаления элемента в избранное * * Функционал: * - Отображает кнопку добавления в избранное * - Кнопка с состояниями (в избранном/не в избранном) * - Плавная анимация при добавлении в избранное * - Задержка перед отображением кнопки удаления из избранного после добавления * * @param file - Объект медиафайла или другого элемента * @param size - Размер кнопки (по умолчанию 150px) * @param type - Тип элемента (по умолчанию "media") */ export const FavoriteButton = memo(function FavoriteButton({ file, size = 150, type = "media" }: FavoriteButtonProps) { const { t } = useTranslation() const { addToFavorites, removeFromFavorites, favorites } = useFavorites() const isFavorite = favorites[type]?.some((f) => f.id === file.id) const [isHovering, setIsHovering] = useState(false) const [isRecentlyAdded, setIsRecentlyAdded] = useState(false) const timerRef = useRef(null) const prevIsFavoriteRef = useRef(isFavorite) useEffect(() => { // Обновляем состояние немедленно при изменении isFavorite if (isFavorite !== prevIsFavoriteRef.current) { // Если элемент добавлен в избранное, устанавливаем флаг isRecentlyAdded if (isFavorite) { setIsRecentlyAdded(true) // Очищаем предыдущий таймер, если он есть if (timerRef.current) { clearTimeout(timerRef.current) } // Через 1 секунду сбрасываем флаг timerRef.current = setTimeout(() => { setIsRecentlyAdded(false) timerRef.current = null }, 1000) } else { // Если элемент удален из избранного, сбрасываем флаг isRecentlyAdded setIsRecentlyAdded(false) // Очищаем таймер if (timerRef.current) { clearTimeout(timerRef.current) timerRef.current = null } } // Обновляем предыдущее значение isFavorite prevIsFavoriteRef.current = isFavorite } // Очищаем таймер при размонтировании компонента return () => { if (timerRef.current) { clearTimeout(timerRef.current) timerRef.current = null } } }, [isFavorite]) // Принудительно обновляем состояние при монтировании компонента useEffect(() => { // Если элемент уже в избранном при монтировании компонента if (isFavorite) { setIsRecentlyAdded(true) prevIsFavoriteRef.current = true // Через 1 секунду сбрасываем флаг const timer = setTimeout(() => { setIsRecentlyAdded(false) }, 1000) return () => clearTimeout(timer) } }, [isFavorite]) // Определяем, можно ли показывать кнопку удаления // Не показываем кнопку удаления в течение 3 секунд после добавления const canShowRemoveButton = !isRecentlyAdded // Регистрируем shortcut action когда кнопка в фокусе useEffect(() => { const handleToggleFavoriteShortcut = () => { // Проверяем, что кнопка или её родительский элемент в фокусе const activeElement = document.activeElement const buttonElement = document.querySelector(`[data-file-id="${file.id}"]`) if (buttonElement && (buttonElement === activeElement || buttonElement.contains(activeElement))) { if (isFavorite && isHovering && canShowRemoveButton) { void removeFromFavorites(file, type) } else if (!isFavorite) { void addToFavorites(file, type) setIsRecentlyAdded(true) } } } shortcutsRegistry.updateAction("toggle-favorite", handleToggleFavoriteShortcut) return () => { shortcutsRegistry.updateAction("toggle-favorite", undefined) } }, [isFavorite, isHovering, canShowRemoveButton, removeFromFavorites, addToFavorites, file, type]) const handleToggleFavorite = useCallback( (e: React.MouseEvent | React.KeyboardEvent) => { e.stopPropagation() e.preventDefault() if (isFavorite && isHovering && canShowRemoveButton) { // Удаляем из избранного void removeFromFavorites(file, type) } else if (!isFavorite) { // Добавляем в избранное void addToFavorites(file, type) // Немедленно обновляем визуальное состояние setIsRecentlyAdded(true) } }, [isFavorite, isHovering, canShowRemoveButton, removeFromFavorites, addToFavorites, file, type], ) return ( ) })