BigBlocks Docs
Components/Social

LikeButton

Add on-chain likes and reactions to social posts using the bSocial protocol

A component for adding on-chain likes and reactions to social posts using the bSocial protocol. Supports emoji reactions, like counts, and real-time updates.

LikeButton DemoAdd on-chain likes and reactions to social posts using the bSocial protocol.
Demo Post #1abc123def456...
Click to like
Demo Post #2def456ghi789...
Click to like
Demo Post #3ghi789jkl012...
Click to like
Different Variants
Small
Medium
Large
Features
On-chain LikesbSocial ProtocolReal-time UpdatesMultiple SizesCustom Styling

Installation

npx bigblocks add like-button

Import

import { LikeButton, SimpleLikeButton, HeartButton } from 'bigblocks';

Props

PropTypeRequiredDefaultDescription
txidstringYes-Transaction ID of the post
emojistringNo'👍'Emoji for the reaction
autoFetchbooleanNotrueAuto-fetch like info
likeInfoLikeInfoNo-Pre-loaded like information
isLikedbooleanNo-Override liked state
currentUserEmojistringNo-User's current emoji reaction
showCountbooleanNotrueShow like count
enableEmojiPickerbooleanNofalseEnable emoji selection
showTooltipbooleanNofalseShow tooltip on hover
onLike(emoji: string) => voidNo-Like callback
onUnlike(emoji: string) => voidNo-Unlike callback
classNamestringNo-Additional CSS classes
variantstringNo-Button variant
sizestringNo-Button size
disabledbooleanNofalseDisable interactions
loadingbooleanNofalseLoading state

Basic Usage

import { LikeButton } from 'bigblocks';

export default function PostActions({ post }) {
  return (
    <LikeButton
      txid={post.txid}
      onLike={(emoji) => {
        console.log(`Liked with ${emoji}`);
      }}
    />
  );
}

Component Variations

SimpleLikeButton

A basic like button without emoji picker:

import { SimpleLikeButton } from 'bigblocks';

export default function SimplePost({ post }) {
  return (
    <SimpleLikeButton
      txid={post.txid}
      emoji="👍"
      onLike={() => console.log('Liked!')}
    />
  );
}

HeartButton

A heart-specific like button:

import { HeartButton } from 'bigblocks';

export default function HeartPost({ post }) {
  return (
    <HeartButton
      txid={post.txid}
      onLike={() => console.log('Hearted!')}
    />
  );
}

Advanced Usage

With Emoji Picker

import { LikeButton } from 'bigblocks';

export default function EmojiReactions({ post }) {
  return (
    <LikeButton
      txid={post.txid}
      enableEmojiPicker={true}
      showTooltip={true}
      onLike={(emoji) => {
        console.log(`Reacted with ${emoji}`);
        // Update local state
      }}
      onUnlike={(emoji) => {
        console.log(`Removed ${emoji} reaction`);
      }}
    />
  );
}

With Pre-loaded Data

import { LikeButton } from 'bigblocks';

export default function PreloadedLikes({ post, likeInfo }) {
  return (
    <LikeButton
      txid={post.txid}
      likeInfo={likeInfo}
      autoFetch={false}
      currentUserEmoji={likeInfo.userReaction}
      onLike={(emoji) => {
        // Handle like
        updateLikeInfo(post.txid, emoji);
      }}
    />
  );
}

Different States

import { LikeButton } from 'bigblocks';

export default function LikeStates({ post }) {
  const [loading, setLoading] = useState(false);

  return (
    <div className="space-y-4">
      {/* Normal state */}
      <LikeButton
        txid={post.txid}
        onLike={() => console.log('Liked')}
      />

      {/* Loading state */}
      <LikeButton
        txid={post.txid}
        loading={true}
        onLike={() => console.log('Liked')}
      />

      {/* Disabled state */}
      <LikeButton
        txid={post.txid}
        disabled={true}
        onLike={() => console.log('Liked')}
      />

      {/* Pre-liked state */}
      <LikeButton
        txid={post.txid}
        isLiked={true}
        currentUserEmoji="❤️"
        onLike={() => console.log('Liked')}
      />
    </div>
  );
}

Custom Styling

import { LikeButton } from 'bigblocks';

export default function StyledLikes({ post }) {
  return (
    <LikeButton
      txid={post.txid}
      className="hover:scale-110 transition-transform"
      variant="ghost"
      size="large"
      showTooltip={true}
      onLike={(emoji) => {
        console.log('Styled like:', emoji);
      }}
    />
  );
}

Common Patterns

In Post Card

import { LikeButton, PostCard } from 'bigblocks';

export default function SocialPost({ post }) {
  return (
    <div className="border rounded-lg p-4">
      <div className="mb-4">
        <h3 className="font-semibold">{post.author.name}</h3>
        <p>{post.content}</p>
      </div>
      
      <div className="flex items-center gap-4">
        <LikeButton
          txid={post.txid}
          enableEmojiPicker={true}
          onLike={(emoji) => {
            // Update post likes
            updatePostLikes(post.txid, emoji);
          }}
        />
        
        <button className="text-gray-500">
          💬 {post.commentCount}
        </button>
        
        <button className="text-gray-500">
          🔄 {post.shareCount}
        </button>
      </div>
    </div>
  );
}

Multiple Reactions

import { LikeButton } from 'bigblocks';

export default function MultipleReactions({ post }) {
  const reactions = ['👍', '❤️', '😂', '😮', '😢', '😡'];

  return (
    <div className="flex items-center gap-2">
      {reactions.map(emoji => (
        <LikeButton
          key={emoji}
          txid={post.txid}
          emoji={emoji}
          showCount={false}
          className="min-w-8"
          onLike={() => {
            console.log(`Reacted with ${emoji}`);
          }}
        />
      ))}
      
      <span className="text-sm text-gray-500 ml-2">
        {post.totalLikes} reactions
      </span>
    </div>
  );
}

With Real-time Updates

import { LikeButton } from 'bigblocks';
import { useEffect, useState } from 'react';

export default function RealtimeLikes({ post }) {
  const [likeInfo, setLikeInfo] = useState(post.likeInfo);

  useEffect(() => {
    // Subscribe to real-time updates
    const eventSource = new EventSource(`/api/social/likes/stream`);
    
    eventSource.onmessage = (event) => {
      const data = JSON.parse(event.data);
      
      if (data.type === 'like_added' && data.postTxid === post.txid) {
        setLikeInfo(prev => ({
          ...prev,
          count: data.count,
          reactions: data.reactions
        }));
      }
    };

    return () => eventSource.close();
  }, [post.txid]);

  return (
    <LikeButton
      txid={post.txid}
      likeInfo={likeInfo}
      enableEmojiPicker={true}
      onLike={(emoji) => {
        // Optimistic update
        setLikeInfo(prev => ({
          ...prev,
          userReaction: emoji,
          count: prev.count + 1
        }));
      }}
    />
  );
}

Error Handling

import { LikeButton } from 'bigblocks';
import { useState } from 'react';

export default function ErrorHandlingLikes({ post }) {
  const [error, setError] = useState(null);

  const handleLike = async (emoji) => {
    try {
      setError(null);
      
      // API call to like post
      await likePost(post.txid, emoji);
      
      toast.success('Liked!');
      
    } catch (err) {
      setError(err.message);
      
      if (err.code === 'INSUFFICIENT_FUNDS') {
        toast.error('Insufficient BSV for like');
      } else if (err.code === 'ALREADY_LIKED') {
        toast.info('Already liked with this emoji');
      } else {
        toast.error('Failed to like post');
      }
    }
  };

  return (
    <div>
      {error && (
        <div className="text-red-500 text-sm mb-2">
          {error}
        </div>
      )}
      
      <LikeButton
        txid={post.txid}
        onLike={handleLike}
      />
    </div>
  );
}

API Reference

This component extends the Button primitive and provides on-chain social reactions using the bSocial protocol.

Types

interface LikeInfo {
  count: number;              // Total likes
  reactions: {
    [emoji: string]: number;  // Count per emoji
  };
  userReaction?: string;      // Current user's emoji
  userLikes: string[];        // All user's emojis
}

interface LikeButtonProps {
  txid: string;               // Post transaction ID
  emoji?: string;             // Default emoji
  autoFetch?: boolean;        // Auto-fetch like data
  likeInfo?: LikeInfo;        // Pre-loaded data
  onLike?: (emoji: string) => void;
  onUnlike?: (emoji: string) => void;
  // ... other props
}

Features

  • Multiple Emojis: Support for any emoji reaction
  • Real-time Counts: Live like count updates
  • Optimistic Updates: Instant visual feedback
  • Emoji Picker: Built-in emoji selection
  • Tooltip Support: Hover information
  • Auto-fetch: Automatic like data loading
  • Variants: Different button styles and behaviors

Requirements

  • Authentication: User must be authenticated
  • Wallet Balance: Sufficient BSV for transaction fees
  • Network: Connection to Bitcoin network
  • Provider Context: BitcoinQueryProvider wrapper

Best Practices

  1. Optimistic Updates: Update UI immediately
  2. Error Handling: Handle network and balance errors
  3. Rate Limiting: Prevent spam clicking
  4. Accessibility: Support keyboard navigation
  5. Performance: Cache like data when possible

Troubleshooting

Likes Not Updating

  • Check authentication status
  • Verify network connectivity
  • Ensure sufficient wallet balance

Emoji Picker Issues

  • Verify enableEmojiPicker is true
  • Check for JavaScript errors
  • Ensure proper event handling

Count Inconsistencies

  • Check real-time update subscription
  • Verify API response format
  • Ensure proper state management

API Integration

The component integrates with bSocial protocol APIs:

// Like a post
POST /api/social/likes
{
  postTxid: string;
  emoji: string;
}

// Unlike a post
DELETE /api/social/likes
{
  postTxid: string;
  emoji: string;
}

// Get like info
GET /api/social/posts/{txid}/likes

Notes for Improvement

Enhanced Implementation: The actual component provides more sophisticated features than the prompt described:

  • Integration with bmap-api-types for proper Bitcoin transaction handling
  • Multiple component variants (Simple, Heart) for different use cases
  • Emoji picker functionality for diverse reactions
  • Auto-fetch capabilities for seamless data loading
  • Better state management with pre-loaded data support