FriendsDialog
Comprehensive friends management dialog with social networking features for Bitcoin-based applications
A comprehensive friends management dialog component that provides social networking functionality including friend lists, friend requests, mutual connections, and social discovery for Bitcoin-based applications. This component enables users to build trusted social networks using their Bitcoin identity as the foundation.
Demo Note: This demonstrates the FriendsDialog component for managing social connections. The dialog includes friend lists, requests, mutual connections, and discovery features.
Installation
npx bigblocks add friends-dialog
Import
import { FriendsDialog } from 'bigblocks';
Props
Prop | Type | Required | Default | Description |
---|---|---|---|---|
isOpen | boolean | Yes | - | Dialog open state |
onClose | () => void | Yes | - | Close dialog callback |
onFriendRequest | (bapId: string) => void | No | - | Send friend request callback |
onAcceptRequest | (requestId: string) => void | No | - | Accept friend request callback |
onRejectRequest | (requestId: string) => void | No | - | Reject friend request callback |
onRemoveFriend | (bapId: string) => void | No | - | Remove existing friend callback |
onBlockUser | (bapId: string) => void | No | - | Block user callback |
onUnblockUser | (bapId: string) => void | No | - | Unblock user callback |
onMessageFriend | (bapId: string) => void | No | - | Start conversation callback |
showMutualFriends | boolean | No | true | Show mutual connections count |
enableFriendSuggestions | boolean | No | true | Show friend suggestions tab |
maxResults | number | No | 50 | Maximum results per section |
className | string | No | - | Additional CSS classes |
Basic Usage
import { FriendsDialog } from 'bigblocks';
import { useState } from 'react';
function SocialApp() {
const [friendsOpen, setFriendsOpen] = useState(false);
return (
<div>
<button onClick={() => setFriendsOpen(true)}>
Friends
</button>
<FriendsDialog
isOpen={friendsOpen}
onClose={() => setFriendsOpen(false)}
onFriendRequest={(bapId) => console.log('Friend request sent to:', bapId)}
onAcceptRequest={(requestId) => console.log('Accepted request:', requestId)}
/>
</div>
);
}
Advanced Usage
With All Features Enabled
<FriendsDialog
isOpen={isOpen}
onClose={handleClose}
onFriendRequest={async (bapId) => {
const result = await sendFriendRequest(bapId);
toast.success('Friend request sent!');
}}
onAcceptRequest={async (requestId) => {
await acceptFriendRequest(requestId);
toast.success('Friend request accepted!');
}}
onRejectRequest={async (requestId) => {
await rejectFriendRequest(requestId);
}}
onRemoveFriend={async (bapId) => {
if (confirm('Remove this friend?')) {
await removeFriend(bapId);
}
}}
onBlockUser={async (bapId) => {
if (confirm('Block this user?')) {
await blockUser(bapId);
toast.info('User blocked');
}
}}
onMessageFriend={(bapId) => {
router.push(`/messages/${bapId}`);
}}
showMutualFriends={true}
enableFriendSuggestions={true}
maxResults={100}
/>
Common Patterns
Social Discovery Integration
function SocialDiscoveryApp() {
const [activeTab, setActiveTab] = useState('friends');
const { user } = useBitcoinAuth();
const { friends, suggestions, nearbyUsers } = useSocialData();
return (
<FriendsDialog
isOpen={true}
onClose={() => {}}
customTabs={[
{
id: 'discovery',
label: 'Discover',
content: (
<div className="discovery-content">
<div className="discovery-filters">
<button
className={activeTab === 'suggested' ? 'active' : ''}
onClick={() => setActiveTab('suggested')}
>
Suggested for You
</button>
<button
className={activeTab === 'nearby' ? 'active' : ''}
onClick={() => setActiveTab('nearby')}
>
Nearby Users
</button>
<button
className={activeTab === 'mutual' ? 'active' : ''}
onClick={() => setActiveTab('mutual')}
>
Friends of Friends
</button>
</div>
{activeTab === 'suggested' && (
<SuggestedUsersList
suggestions={suggestions}
onConnect={(bapId) => sendFriendRequest(bapId)}
/>
)}
{activeTab === 'nearby' && (
<NearbyUsersList
users={nearbyUsers}
onConnect={(bapId) => sendFriendRequest(bapId)}
/>
)}
{activeTab === 'mutual' && (
<MutualFriendsList
friends={friends}
onConnect={(bapId) => sendFriendRequest(bapId)}
/>
)}
</div>
)
}
]}
/>
);
}
Gaming Friends System
function GamingFriendsManager() {
const { onlineFriends, recentlyPlayed } = useGamingFriends();
return (
<FriendsDialog
isOpen={true}
onClose={() => {}}
customTabs={[
{
id: 'online',
label: `Online (${onlineFriends.length})`,
content: (
<div className="online-friends">
{onlineFriends.map(friend => (
<div key={friend.bapId} className="online-friend">
<div className="friend-status online" />
<BitcoinAvatar
src={friend.avatar}
name={friend.name}
size="small"
/>
<div className="friend-info">
<h5>{friend.name}</h5>
<p className="playing-game">
Playing: {friend.currentGame}
</p>
</div>
<div className="friend-actions">
<button onClick={() => inviteToGame(friend.bapId)}>
Invite
</button>
<button onClick={() => joinGame(friend.gameId)}>
Join
</button>
</div>
</div>
))}
</div>
)
}
]}
/>
);
}
Professional Networking
function ProfessionalNetwork() {
const { connections, pendingConnections } = useProfessionalNetwork();
return (
<FriendsDialog
isOpen={true}
onClose={() => {}}
showMutualFriends={true}
customTabs={[
{
id: 'connections',
label: 'My Network',
content: (
<div className="professional-network">
{connections.map(connection => (
<div key={connection.bapId} className="connection-card">
<BitcoinAvatar
src={connection.avatar}
name={connection.name}
/>
<div className="connection-details">
<h4>{connection.name}</h4>
<p className="title">{connection.title}</p>
<p className="company">{connection.company}</p>
<div className="mutual-info">
{connection.mutualConnections} mutual connections
</div>
</div>
<button
className="message-btn"
onClick={() => startConversation(connection.bapId)}
>
Message
</button>
</div>
))}
</div>
)
}
]}
/>
);
}
Authentication Requirements
The FriendsDialog component requires proper Bitcoin authentication context:
import {
BitcoinAuthProvider,
BitcoinQueryProvider,
BitcoinThemeProvider
} from 'bigblocks';
function App() {
return (
<BitcoinQueryProvider>
<BitcoinAuthProvider config={{ apiUrl: '/api' }}>
<BitcoinThemeProvider>
<YourAppWithFriendsDialog />
</BitcoinThemeProvider>
</BitcoinAuthProvider>
</BitcoinQueryProvider>
);
}
API Reference
This component extends the Dialog primitive and provides comprehensive social networking functionality for Bitcoin-based applications.
API Integration
The FriendsDialog component typically requires these backend endpoints:
Friend Management
GET /api/friends
- Fetch user's friend listPOST /api/friends/request
- Send friend requestPOST /api/friends/accept
- Accept friend requestPOST /api/friends/reject
- Reject friend requestDELETE /api/friends/:bapId
- Remove friendPOST /api/friends/block
- Block userDELETE /api/friends/block/:bapId
- Unblock user
Social Discovery
GET /api/friends/suggestions
- Get friend suggestionsGET /api/friends/mutual/:bapId
- Get mutual friendsGET /api/friends/nearby
- Get nearby users (if location enabled)
Example API Implementation
// /api/friends/request
export async function POST(request: Request) {
const { bapId } = await request.json();
const session = await getSession();
if (!session?.user?.bapId) {
return new Response('Unauthorized', { status: 401 });
}
// Create friend request with Bitcoin signature
const requestData = {
from: session.user.bapId,
to: bapId,
timestamp: Date.now(),
status: 'pending'
};
// Sign the request with user's Bitcoin key
const signature = await signWithBitcoin(requestData);
// Store in database
await redis.hset(
`friend-requests:${bapId}`,
session.user.bapId,
JSON.stringify({ ...requestData, signature })
);
return Response.json({ success: true, requestId: signature });
}
Troubleshooting
Friends List Not Loading
// Ensure BitcoinQueryProvider is wrapping the component
<BitcoinQueryProvider>
<FriendsDialog {...props} />
</BitcoinQueryProvider>
Friend Requests Not Working
// Check that callbacks are properly async
onFriendRequest={async (bapId) => {
try {
await sendFriendRequest(bapId);
} catch (error) {
console.error('Friend request failed:', error);
}
}}
Real-time Updates Not Working
// Implement WebSocket or polling for real-time updates
useEffect(() => {
const interval = setInterval(() => {
refetchFriends();
refetchRequests();
}, 30000); // Poll every 30 seconds
return () => clearInterval(interval);
}, []);
Related Components
- SocialFeed - Display social posts from friends
- ProfileCard - Show user profile information
- MessageDisplay - Display messages between friends
- FollowButton - Simple follow/unfollow functionality
- ProfileDropdownMenu - Quick profile actions
Advanced Features
Custom Tab Implementation
interface CustomTab {
id: string;
label: string;
content: React.ReactNode;
badge?: number;
}
const customTabs: CustomTab[] = [
{
id: 'groups',
label: 'Groups',
badge: 3,
content: <GroupsList />
},
{
id: 'events',
label: 'Events',
content: <EventInvitations />
}
];
<FriendsDialog
customTabs={customTabs}
defaultTab="groups"
/>
Friend Filtering and Sorting
const [sortBy, setSortBy] = useState<'name' | 'activity' | 'reputation'>('name');
const [filterBy, setFilterBy] = useState<'all' | 'online' | 'verified'>('all');
const filteredFriends = useMemo(() => {
return friends
.filter(friend => {
if (filterBy === 'online') return friend.isOnline;
if (filterBy === 'verified') return friend.verified;
return true;
})
.sort((a, b) => {
switch (sortBy) {
case 'name':
return a.name.localeCompare(b.name);
case 'activity':
return b.lastSeen - a.lastSeen;
case 'reputation':
return b.reputation - a.reputation;
default:
return 0;
}
});
}, [friends, sortBy, filterBy]);
Privacy Controls
const privacySettings = {
showOnlineStatus: true,
allowFriendRequests: true,
showMutualFriends: true,
requireApproval: true,
blockList: ['bapId1', 'bapId2']
};
<FriendsDialog
privacySettings={privacySettings}
onUpdatePrivacy={(newSettings) => updatePrivacySettings(newSettings)}
/>
Security Considerations
- Bitcoin Signature Verification: All friend operations should be signed with the user's Bitcoin private key
- Privacy Settings: Respect user privacy preferences when displaying mutual friends or online status
- Rate Limiting: Implement rate limits on friend requests to prevent spam
- Block List Management: Ensure blocked users cannot view any information about the blocking user
- Data Encryption: Consider encrypting sensitive friend data in transit and at rest
Best Practices
- Pagination: For large friend lists, implement virtual scrolling or pagination
- Caching: Use React Query or similar for efficient data caching
- Optimistic Updates: Update UI immediately while API calls complete
- Error Handling: Provide clear feedback for failed operations
- Mobile Responsiveness: Ensure the dialog works well on mobile devices
- Accessibility: Include proper ARIA labels and keyboard navigation