import { useState, useEffect } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Button } from '@/components/ui/button'; import { UserPlus, UserCheck, Loader2 } from 'lucide-react'; import { cn } from '@/lib/utils'; import { followPlaylist, unfollowPlaylist, getPlaylist, getPlaylistFollowStatus, } from '../services/playlistService'; import type { Playlist } from '../types'; import { useToast } from '@/hooks/useToast'; import { useUser } from '@/features/auth/hooks/useUser'; /** * FE-COMP-017: Follow/Unfollow button component for playlists */ interface PlaylistFollowButtonProps { playlistId: string; initialFollowing?: boolean; initialFollowerCount?: number; onFollowChange?: (isFollowing: boolean) => void; className?: string; size?: 'default' | 'sm' | 'lg' | 'icon'; variant?: 'default' | 'outline' | 'ghost'; showCount?: boolean; } export function PlaylistFollowButton({ playlistId, initialFollowing = false, initialFollowerCount = 0, onFollowChange, className, size = 'default', variant, showCount = false, }: PlaylistFollowButtonProps) { const { data: user } = useUser(); const { success: showSuccess, error: showError } = useToast(); const queryClient = useQueryClient(); const [following, setFollowing] = useState(initialFollowing); const [followerCount, setFollowerCount] = useState(initialFollowerCount); const [isUpdating, setIsUpdating] = useState(false); // Fetch playlist to get current follow status const { data: playlist } = useQuery({ queryKey: ['playlist', playlistId], queryFn: () => getPlaylist(playlistId), enabled: !!playlistId && !!user, staleTime: 30000, // 30 seconds }); // Try to fetch follow status if available const { data: followStatus } = useQuery({ queryKey: ['playlistFollowStatus', playlistId], queryFn: () => getPlaylistFollowStatus(playlistId), enabled: !!playlistId && !!user, staleTime: 30000, retry: false, }); // Update state from API response useEffect(() => { if (followStatus) { setFollowing(followStatus.is_following); setFollowerCount(followStatus.follower_count); } else if (playlist && (playlist as any).is_following !== undefined) { setFollowing((playlist as any).is_following); } else if (initialFollowing !== undefined) { setFollowing(initialFollowing); } if (playlist && (playlist as any).follower_count !== undefined) { setFollowerCount((playlist as any).follower_count); } else if (initialFollowerCount !== undefined) { setFollowerCount(initialFollowerCount); } }, [followStatus, playlist, initialFollowing, initialFollowerCount]); // Follow mutation const followMutation = useMutation({ mutationFn: () => followPlaylist(playlistId), onMutate: async () => { // Optimistic update setFollowing(true); setFollowerCount((prev) => prev + 1); setIsUpdating(true); }, onSuccess: () => { showSuccess('Vous suivez maintenant cette playlist'); onFollowChange?.(true); // Invalidate queries to refresh data queryClient.invalidateQueries({ queryKey: ['playlist', playlistId] }); queryClient.invalidateQueries({ queryKey: ['playlistFollowStatus', playlistId], }); queryClient.invalidateQueries({ queryKey: ['playlists'] }); }, onError: (error: any) => { // Revert optimistic update setFollowing(false); setFollowerCount((prev) => Math.max(0, prev - 1)); const errorMessage = error.response?.data?.error?.message || error.response?.data?.message || error.message || "Erreur lors de l'abonnement à la playlist"; showError(errorMessage); }, onSettled: () => { setIsUpdating(false); }, }); // Unfollow mutation const unfollowMutation = useMutation({ mutationFn: () => unfollowPlaylist(playlistId), onMutate: async () => { // Optimistic update setFollowing(false); setFollowerCount((prev) => Math.max(0, prev - 1)); setIsUpdating(true); }, onSuccess: () => { showSuccess('Vous ne suivez plus cette playlist'); onFollowChange?.(false); // Invalidate queries to refresh data queryClient.invalidateQueries({ queryKey: ['playlist', playlistId] }); queryClient.invalidateQueries({ queryKey: ['playlistFollowStatus', playlistId], }); queryClient.invalidateQueries({ queryKey: ['playlists'] }); }, onError: (error: any) => { // Revert optimistic update setFollowing(true); setFollowerCount((prev) => prev + 1); const errorMessage = error.response?.data?.error?.message || error.response?.data?.message || error.message || 'Erreur lors du désabonnement de la playlist'; showError(errorMessage); }, onSettled: () => { setIsUpdating(false); }, }); const handleClick = (e: React.MouseEvent) => { e.stopPropagation(); if (isUpdating || !user) return; if (following) { unfollowMutation.mutate(); } else { followMutation.mutate(); } }; // Don't show follow button if user is not logged in or is the owner if (!user || user.id === playlist?.user_id) { return null; } const isLoading = followMutation.isPending || unfollowMutation.isPending || isUpdating; const buttonVariant = variant || (following ? 'outline' : 'default'); return ( ); }