diff --git a/src/components/__tests__/FollowButton.test.tsx b/src/components/__tests__/FollowButton.test.tsx new file mode 100644 index 00000000..002529ee --- /dev/null +++ b/src/components/__tests__/FollowButton.test.tsx @@ -0,0 +1 @@ +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { describe, it, expect, vi } from 'vitest'; import FollowButton from '../common/FollowButton'; describe('FollowButton', () => { it('renders Follow when not following', () => { render(); expect(screen.getByTestId('follow-button')).toHaveTextContent('Follow'); }); it('renders Following when following', () => { render(); expect(screen.getByTestId('follow-button')).toHaveTextContent('Following'); }); it('calls onFollow with correct address when not following', async () => { const onFollow = vi.fn().mockResolvedValue(undefined); render(); fireEvent.click(screen.getByTestId('follow-button')); await waitFor(() => expect(onFollow).toHaveBeenCalledWith('0x123')); }); it('calls onUnfollow when already following', async () => { const onUnfollow = vi.fn().mockResolvedValue(undefined); render(); fireEvent.click(screen.getByTestId('follow-button')); await waitFor(() => expect(onUnfollow).toHaveBeenCalled()); }); it('disables button and shows loading while pending', async () => { const onFollow = vi.fn().mockImplementation(() => new Promise(resolve => setTimeout(resolve, 100))); render(); fireEvent.click(screen.getByTestId('follow-button')); expect(screen.getByTestId('follow-button')).toBeDisabled(); expect(screen.getByTestId('follow-button')).toHaveTextContent('Loading...'); await waitFor(() => expect(onFollow).toHaveBeenCalled()); }); }); \ No newline at end of file diff --git a/src/components/common/FollowButton.tsx b/src/components/common/FollowButton.tsx new file mode 100644 index 00000000..8d88d30d --- /dev/null +++ b/src/components/common/FollowButton.tsx @@ -0,0 +1,42 @@ +import { useState } from 'react'; +import { Button } from '@/components/ui/button'; + +interface FollowButtonProps { + creatorAddress: string; + isFollowing: boolean; + onFollow: (creatorAddress: string) => Promise; + onUnfollow: (creatorAddress: string) => Promise; +} + +export default function FollowButton({ + creatorAddress, + isFollowing, + onFollow, + onUnfollow, +}: FollowButtonProps) { + const [loading, setLoading] = useState(false); + + const handleClick = async () => { + setLoading(true); + try { + if (isFollowing) { + await onUnfollow(creatorAddress); + } else { + await onFollow(creatorAddress); + } + } finally { + setLoading(false); + } + }; + + return ( + + ); +} \ No newline at end of file