Components/Profiles
ProfileViewer
Display a complete view of a BAP profile with avatar, information, actions, and status
A component for displaying a complete view of a BAP (Bitcoin Attestation Protocol) profile, including avatar, profile information, Bitcoin address, publication status, and action buttons.
Installation
npx bigblocks add profile-viewer
Import
import { ProfileViewer } from 'bigblocks';
Props
Prop | Type | Required | Default | Description |
---|---|---|---|---|
profile | ProfileInfo | Yes | - | Profile data to display |
showAddress | boolean | No | true | Show Bitcoin address with copy function |
showPublishStatus | boolean | No | true | Show published/unpublished status |
showActions | boolean | No | true | Show edit and publish buttons |
onEdit | () => void | No | - | Edit button click handler |
onPublish | () => void | No | - | Publish button click handler |
className | string | No | - | Additional CSS classes |
variant | 'surface' | 'classic' | 'ghost' | No | 'surface' | Visual style variant |
size | '1' | '2' | '3' | '4' | No | '3' | Component size |
Basic Usage
import { ProfileViewer } from 'bigblocks';
export default function UserProfile() {
const profile = {
id: 'bap-123',
address: '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
isPublished: true,
name: 'Bitcoin Builder',
alternateName: '@btc_builder',
description: 'Building the future of money on Bitcoin',
image: 'https://api.dicebear.com/7.x/avataaars/svg?seed=builder',
url: 'https://bitcoin.org',
email: 'builder@bitcoin.org',
paymail: 'builder@moneybutton.com'
};
return (
<ProfileViewer
profile={profile}
onEdit={() => {
console.log('Edit profile');
}}
onPublish={() => {
console.log('Publish profile');
}}
/>
);
}
Profile Structure
interface ProfileInfo {
id: string; // Profile identifier
address: string; // Bitcoin address
isPublished: boolean; // Publication status
// Basic Information
'@context'?: string; // JSON-LD context
'@type'?: 'Person' | 'Organization';
name?: string; // Display name
alternateName?: string; // Username/handle
description?: string; // Bio/description
// Images
image?: string; // Avatar/profile image
logo?: string; // Organization logo
banner?: string; // Banner/cover image
// Contact Information
url?: string; // Website URL
email?: string; // Email address
paymail?: string; // Bitcoin paymail
bitcoinAddress?: string; // Additional Bitcoin address
// Personal Details
givenName?: string; // First name
familyName?: string; // Last name
legalName?: string; // Legal/full name
// Location Information
location?: string; // General location
homeLocation?: string; // Home location
streetAddress?: string; // Street address
addressLocality?: string; // City
addressRegion?: string; // State/province
postalCode?: string; // ZIP/postal code
addressCountry?: string; // Country
}
Advanced Usage
Complete Profile with All Fields
import { ProfileViewer } from 'bigblocks';
export default function CompleteProfile() {
const profile = {
id: 'bap-456',
address: '1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2',
isPublished: true,
'@context': 'https://schema.org',
'@type': 'Person',
name: 'Satoshi Nakamoto',
alternateName: '@satoshi',
description: 'Creator of Bitcoin. Pseudonymous developer who designed and implemented the world\'s first cryptocurrency.',
image: 'https://api.dicebear.com/7.x/avataaars/svg?seed=satoshi',
banner: 'https://images.unsplash.com/photo-1640340434855-6084b1f4901c',
url: 'https://bitcoin.org',
email: 'satoshi@gmx.com',
paymail: 'satoshi@relayx.io',
givenName: 'Satoshi',
familyName: 'Nakamoto',
location: 'Worldwide',
bitcoinAddress: '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa'
};
return (
<ProfileViewer
profile={profile}
variant="surface"
size="4"
onEdit={() => {
// Open profile editor
setEditMode(true);
}}
onPublish={() => {
// Publish to blockchain
publishProfile(profile.id);
}}
/>
);
}
Read-only Profile View
import { ProfileViewer } from 'bigblocks';
export default function PublicProfile({ profile }) {
return (
<ProfileViewer
profile={profile}
showActions={false}
showPublishStatus={false}
variant="classic"
/>
);
}
Organization Profile
import { ProfileViewer } from 'bigblocks';
export default function CompanyProfile() {
const orgProfile = {
id: 'org-789',
address: '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy',
isPublished: true,
'@type': 'Organization',
name: 'Bitcoin Foundation',
legalName: 'Bitcoin Foundation, Inc.',
description: 'Promoting the responsible adoption of Bitcoin through education, advocacy, and ecosystem development.',
logo: 'https://bitcoinfoundation.org/logo.png',
banner: 'https://bitcoinfoundation.org/banner.jpg',
url: 'https://bitcoinfoundation.org',
email: 'info@bitcoinfoundation.org',
streetAddress: '1230 NE 3rd Avenue',
addressLocality: 'Miami',
addressRegion: 'FL',
postalCode: '33132',
addressCountry: 'US'
};
return (
<ProfileViewer
profile={orgProfile}
size="4"
onEdit={() => editOrganization(orgProfile.id)}
onPublish={() => publishOrganization(orgProfile.id)}
/>
);
}
With Custom Styling
import { ProfileViewer } from 'bigblocks';
export default function StyledProfile({ profile }) {
return (
<ProfileViewer
profile={profile}
className="shadow-lg border-2 border-orange-200"
variant="ghost"
size="3"
onEdit={() => {
// Custom edit handler
}}
/>
);
}
Different Variants
import { ProfileViewer } from 'bigblocks';
export default function ProfileVariants({ profile }) {
return (
<div className="space-y-6">
{/* Surface variant - default */}
<ProfileViewer
profile={profile}
variant="surface"
onEdit={() => console.log('Edit surface')}
/>
{/* Classic variant */}
<ProfileViewer
profile={profile}
variant="classic"
onEdit={() => console.log('Edit classic')}
/>
{/* Ghost variant */}
<ProfileViewer
profile={profile}
variant="ghost"
onEdit={() => console.log('Edit ghost')}
/>
</div>
);
}
Different Sizes
import { ProfileViewer } from 'bigblocks';
export default function ProfileSizes({ profile }) {
return (
<div className="grid grid-cols-2 gap-4">
{/* Small */}
<ProfileViewer
profile={profile}
size="1"
onEdit={() => console.log('Edit small')}
/>
{/* Medium */}
<ProfileViewer
profile={profile}
size="2"
onEdit={() => console.log('Edit medium')}
/>
{/* Large */}
<ProfileViewer
profile={profile}
size="3"
onEdit={() => console.log('Edit large')}
/>
{/* Extra Large */}
<ProfileViewer
profile={profile}
size="4"
onEdit={() => console.log('Edit extra large')}
/>
</div>
);
}
Common Patterns
Profile Page Layout
import { ProfileViewer, SocialFeed } from 'bigblocks';
export default function ProfilePage({ userId }) {
const [profile, setProfile] = useState(null);
const [isEditing, setIsEditing] = useState(false);
useEffect(() => {
const loadProfile = async () => {
const profileData = await fetchProfile(userId);
setProfile(profileData);
};
loadProfile();
}, [userId]);
const handleEdit = () => {
setIsEditing(true);
};
const handlePublish = async () => {
try {
await publishProfileToBlockchain(profile.id);
setProfile(prev => ({ ...prev, isPublished: true }));
toast.success('Profile published to blockchain!');
} catch (error) {
toast.error('Failed to publish profile');
}
};
if (!profile) return <div>Loading...</div>;
return (
<div className="max-w-4xl mx-auto space-y-6">
<ProfileViewer
profile={profile}
onEdit={handleEdit}
onPublish={handlePublish}
/>
<div className="mt-8">
<SocialFeed
feedType="user"
userId={userId}
/>
</div>
</div>
);
}
Profile Comparison
import { ProfileViewer } from 'bigblocks';
export default function ProfileComparison({ profiles }) {
return (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{profiles.map(profile => (
<ProfileViewer
key={profile.id}
profile={profile}
showActions={false}
variant="classic"
size="3"
/>
))}
</div>
);
}
Profile with Conditional Actions
import { ProfileViewer } from 'bigblocks';
import { useAuth } from 'bigblocks';
export default function ConditionalProfile({ profile }) {
const { user, isAuthenticated } = useAuth();
const isOwnProfile = isAuthenticated && user?.id === profile.id;
const canEdit = isOwnProfile || user?.isAdmin;
return (
<ProfileViewer
profile={profile}
showActions={canEdit}
showPublishStatus={isOwnProfile}
onEdit={canEdit ? () => editProfile(profile.id) : undefined}
onPublish={isOwnProfile ? () => publishProfile(profile.id) : undefined}
/>
);
}
Profile with Status Updates
import { ProfileViewer } from 'bigblocks';
import { useState, useEffect } from 'react';
export default function LiveProfile({ profileId }) {
const [profile, setProfile] = useState(null);
const [publishing, setPublishing] = useState(false);
useEffect(() => {
// Subscribe to profile updates
const unsubscribe = subscribeToProfile(profileId, (updatedProfile) => {
setProfile(updatedProfile);
});
return unsubscribe;
}, [profileId]);
const handlePublish = async () => {
setPublishing(true);
try {
await publishProfile(profileId);
// Profile update will come through subscription
} catch (error) {
console.error('Publish failed:', error);
} finally {
setPublishing(false);
}
};
return (
<div>
{publishing && (
<div className="mb-4 p-3 bg-blue-100 text-blue-700 rounded">
Publishing profile to blockchain...
</div>
)}
<ProfileViewer
profile={profile}
onPublish={handlePublish}
onEdit={() => editProfile(profileId)}
/>
</div>
);
}
Mobile Responsive Profile
import { ProfileViewer } from 'bigblocks';
export default function MobileProfile({ profile }) {
return (
<div className="px-4">
<ProfileViewer
profile={profile}
size="2" // Smaller on mobile
className="w-full"
onEdit={() => {
// Open mobile-friendly editor
openMobileEditor(profile.id);
}}
/>
</div>
);
}
Publishing Status
The component displays different states based on isPublished
:
Published Profile
- ✅ Green checkmark with "Published" text
- Profile data is on the blockchain
- Publicly discoverable
Unpublished Profile
- ⏳ Orange indicator with "Draft" text
- Profile exists locally only
- Not yet on blockchain
Features
- Complete Profile Display: Avatar, name, description, and all profile fields
- Bitcoin Address: Displayed with copy-to-clipboard functionality
- Publication Status: Visual indicator of blockchain publication state
- Action Buttons: Edit and publish controls when enabled
- Responsive Design: Adapts to different screen sizes
- Multiple Variants: Surface, classic, and ghost styling options
- Size Options: Four different size presets
- Type Support: Both Person and Organization profiles
- Schema.org Compliance: Structured data format support
Address Display
When showAddress
is true, the Bitcoin address is displayed with:
- Truncated format for readability
- Copy-to-clipboard button
- Tooltip showing full address
- Visual feedback on copy
Action Buttons
When showActions
is true, displays:
- Edit Button: Opens profile editor (requires
onEdit
handler) - Publish Button: Publishes to blockchain (requires
onPublish
handler)
Accessibility
- Screen reader support for all content
- Keyboard navigation for interactive elements
- High contrast support
- Focus indicators on actionable items
- Alternative text for images
Best Practices
- Complete Profiles: Encourage users to fill all relevant fields
- Image Optimization: Use optimized images for avatars and banners
- Privacy Awareness: Remind users that published data is permanent
- Error Handling: Handle missing or invalid profile data gracefully
- Performance: Lazy load large images and banners
Troubleshooting
Profile Not Displaying
- Check that profile object has required
id
andaddress
fields - Verify profile data structure matches
ProfileInfo
interface - Ensure component is wrapped in proper providers
Images Not Loading
- Verify image URLs are accessible
- Check for CORS issues with external images
- Provide fallback images for missing avatars
Actions Not Working
- Ensure
onEdit
andonPublish
handlers are provided - Check that
showActions
is true (default) - Verify user permissions for profile actions
Related Components
- ProfileEditor - Edit profiles
- ProfileManager - Manage multiple profiles
- ProfileDropdownMenu - Profile selection
- ProfilePopover - Quick profile preview
API Integration
The component works with BAP profile APIs:
// Get profile data
GET /api/bap/profiles/{id}
// Publish profile
POST /api/bap/profiles/{id}/publish
// Update profile
PUT /api/bap/profiles/{id}
Notes for Improvement
Enhanced Implementation: The actual component provides more sophisticated features than the basic prompt described:
- Complete BAP profile schema support with all schema.org fields
- Multiple visual variants and size options for different use cases
- Advanced status indicators for publication state
- Better address handling with copy functionality
- Support for both Person and Organization profile types
- Responsive design optimizations for mobile devices