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
Prop | Type | Required | Default | Description |
---|---|---|---|---|
txid | string | Yes | - | Transaction ID of the post |
emoji | string | No | '👍' | Emoji for the reaction |
autoFetch | boolean | No | true | Auto-fetch like info |
likeInfo | LikeInfo | No | - | Pre-loaded like information |
isLiked | boolean | No | - | Override liked state |
currentUserEmoji | string | No | - | User's current emoji reaction |
showCount | boolean | No | true | Show like count |
enableEmojiPicker | boolean | No | false | Enable emoji selection |
showTooltip | boolean | No | false | Show tooltip on hover |
onLike | (emoji: string) => void | No | - | Like callback |
onUnlike | (emoji: string) => void | No | - | Unlike callback |
className | string | No | - | Additional CSS classes |
variant | string | No | - | Button variant |
size | string | No | - | Button size |
disabled | boolean | No | false | Disable interactions |
loading | boolean | No | false | Loading 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
- Optimistic Updates: Update UI immediately
- Error Handling: Handle network and balance errors
- Rate Limiting: Prevent spam clicking
- Accessibility: Support keyboard navigation
- 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
Related Components
- PostButton - Create posts
- FollowButton - Follow users
- PostCard - Display posts
- SocialFeed - Social feed
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