Follow

Engagement

Add follow/unfollow functionality to user profiles.

Demo

564 followers

Install via CLI

npx feature101@latest add follow
components/FollowButton.ts
"use client";

import { memo } from "react";
import { useFollow } from "../follow.hooks";
import type { FollowButtonProps } from "../follow.types";

const FollowButton = memo(
  ({
    currentUserId,
    targetUserId,
    initialIsFollowing,
    initialFollowerCount,
    showCount = true,
    className = "",
    onFollowChange,
  }: FollowButtonProps) => {
    const { isFollowing, followerCount, isLoading, error, toggleFollow } =
      useFollow({
        currentUserId,
        targetUserId,
        initialIsFollowing,
        initialFollowerCount,
      });

    const handleClick = async () => {
      await toggleFollow();
      onFollowChange?.(!isFollowing);
    };

    // Don't show button if trying to follow yourself
    if (currentUserId === targetUserId) {
      return null;
    }

    return (
      <div className={`inline-flex items-center gap-2 ${className}`}>
        <button
          onClick={handleClick}
          disabled={isLoading}
          className={`
    px-4 py-2 rounded-lg font-medium transition-all
    min-w-25 h-10 flex items-center justify-center
    ${
      isFollowing
        ? "bg-gray-200 text-gray-800 hover:bg-gray-300"
        : "bg-blue-500 text-white hover:bg-blue-600"
    }
    disabled:opacity-50 
  `}
          aria-label={isFollowing ? "Unfollow" : "Follow"}
        >
          {isLoading ? (
            <svg
              className="animate-spin h-5 w-5 mx-auto"
              xmlns="http://www.w3.org/2000/svg"
              fill="none"
              viewBox="0 0 24 24"
            >
              <circle
                className="opacity-25"
                cx="12"
                cy="12"
                r="10"
                stroke="currentColor"
                strokeWidth="4"
              />
              <path
                className="opacity-75"
                fill="currentColor"
                d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
              />
            </svg>
          ) : isFollowing ? (
            "Following"
          ) : (
            "Follow"
          )}
        </button>
        {showCount && (
          <span className="text-sm text-gray-600">
            {followerCount} {followerCount === 1 ? "follower" : "followers"}
          </span>
        )}

        {error && <span className="text-xs text-red-500">{error}</span>}
      </div>
    );
  },
);
FollowButton.displayName = "FollowButton";

export default FollowButton;