'use client'; import { useState, useCallback, useEffect, useRef } from 'react'; import { useSession, signIn } from 'next-auth/react'; import { useTranslations, useLocale } from 'next-intl'; import { Heart, ExternalLink } from 'lucide-react'; import { fetchWithCsrf } from '@/lib/csrf-client'; const isMirror = process.env.NEXT_PUBLIC_IS_PRIMARY === 'false'; const PRIMARY_URL = process.env.NEXT_PUBLIC_PRIMARY_URL || process.env.NEXT_PUBLIC_APP_URL || 'https://skills.palebluedot.live'; interface FavoriteButtonProps { skillId: string; initialFavorited?: boolean; size?: 'sm' | 'md' | 'lg'; showLabel?: boolean; onToggle?: (favorited: boolean) => void; } export function FavoriteButton({ skillId, initialFavorited = false, size = 'md', showLabel = false, onToggle, }: FavoriteButtonProps) { const { data: session, status } = useSession(); const t = useTranslations('favorites'); const locale = useLocale(); const [isFavorited, setIsFavorited] = useState(initialFavorited); const [isLoading, setIsLoading] = useState(false); const [mirrorNotice, setMirrorNotice] = useState(false); const pendingRef = useRef(false); // Fetch actual favorite status when user is authenticated useEffect(() => { if (initialFavorited || status !== 'authenticated') return; let cancelled = false; fetchWithCsrf('/api/favorites/check', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ skillIds: [skillId] }), }) .then((res) => res.ok ? res.json() : null) .then((data) => { if (!cancelled && data?.favorited?.[skillId]) { setIsFavorited(true); } }) .catch(() => {}); return () => { cancelled = true; }; }, [skillId, status, initialFavorited]); // Auto-dismiss mirror notice useEffect(() => { if (!mirrorNotice) return; const timer = setTimeout(() => setMirrorNotice(false), 4000); return () => clearTimeout(timer); }, [mirrorNotice]); const sizeClasses = { sm: 'w-4 h-4', md: 'w-5 h-5', lg: 'w-6 h-6', }; const buttonSizeClasses = { sm: 'p-1.5', md: 'p-2', lg: 'p-2.5', }; const handleToggle = useCallback(async () => { if (pendingRef.current) return; if (status === 'loading') return; if (!session) { signIn('github'); return; } if (isMirror) { setMirrorNotice(true); return; } pendingRef.current = true; const newState = !isFavorited; setIsFavorited(newState); // Optimistic update setIsLoading(true); try { const res = await fetchWithCsrf('/api/favorites', { method: newState ? 'POST' : 'DELETE', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ skillId }), }); if (!res.ok) throw new Error('Failed to update favorite'); onToggle?.(newState); } catch (error) { setIsFavorited(!newState); // Rollback on error console.error('Favorite error:', error); } finally { pendingRef.current = false; setIsLoading(false); } }, [session, status, isFavorited, skillId, onToggle]); const mirrorMsg = locale === 'fa' ? 'برای افزودن به علاقه‌مندی‌ها، از سایت اصلی استفاده کنید' : 'To add favorites, visit the main site'; return ( {mirrorNotice && (
{mirrorMsg}
)}
); }