AssistantLinkPreview Component

The AssistantLinkPreview component provides rich preview cards for AI assistants with tool information and usage statistics.

Overview

This component fetches and displays detailed assistant information in a compact card format. It shows assistant metadata, avatar, tools, documents, and usage statistics with interactive elements for opening the assistant in a new tab.

Location

src/components/AssistantLinkPreview.tsx

Features

Rich Preview Information

  • Assistant Details: Name, owner, and initial message
  • Avatar Display: Assistant avatar with fallback to initials
  • Tool Information: Count and categorized preview of available tools
  • Document Count: Number of attached initial documents
  • Usage Statistics: Total usage count with proper pluralization

Interactive Elements

  • External Link: Opens assistant in new tab
  • Tool Tooltip: Hover to see categorized tool preview
  • Loading States: Smooth loading animation during data fetch
  • Error Handling: Graceful display of error states

Responsive Design

  • Compact Layout: Optimized for embedding in various contexts
  • Text Truncation: Automatically truncates long descriptions
  • Hover Effects: Subtle shadow transition on hover

Props Interface

interface AssistantLinkPreviewProps {
  assistantId: string;    // Unique identifier for the assistant
  className?: string;     // Optional CSS classes
}

Usage Example

import { AssistantLinkPreview } from '@/components/AssistantLinkPreview';

function AssistantMention({ assistantId }) {
  return (
    <div className="my-4">
      <AssistantLinkPreview 
        assistantId={assistantId}
        className="max-w-sm"
      />
    </div>
  );
}

// In markdown or rich text
function MessageContent({ content }) {
  // Automatically render assistant previews for links
  return (
    <div>
      {content.includes('/assistant/') && (
        <AssistantLinkPreview assistantId={extractAssistantId(content)} />
      )}
    </div>
  );
}

State Management

Loading State

const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [assistant, setAssistant] = useState<Assistant | null>(null);

Data Fetching

useEffect(() => {
  const fetchAssistant = async () => {
    try {
      setLoading(true);
      setError(null);
      const assistantData = await FirebaseService.getAssistant(assistantId);
      setAssistant(assistantData);
    } catch (err) {
      console.error('Error fetching assistant preview:', err);
      setError('Failed to load assistant');
    } finally {
      setLoading(false);
    }
  };

  if (assistantId) {
    fetchAssistant();
  }
}, [assistantId]);

Display Components

Loading State

<Card className="w-full max-w-md">
  <CardContent className="flex items-center justify-center p-4">
    <Loader2 className="h-4 w-4 animate-spin mr-2" />
    <span className="text-sm text-muted-foreground">Loading assistant...</span>
  </CardContent>
</Card>

Error State

<Card className="w-full max-w-md border-destructive/20">
  <CardContent className="p-4">
    <p className="text-sm text-destructive">
      {error || 'Assistant not found'}
    </p>
  </CardContent>
</Card>

Success State Structure

  • Header: Avatar, name, owner, external link button
  • Content: Initial message (truncated), tool/document counts, usage stats
  • Tool Tooltip: Categorized tool preview on hover

Text Truncation

const truncateText = (text: string, maxLength: number) => {
  if (text.length <= maxLength) return text;
  return text.slice(0, maxLength) + '...';
};

// Applied to initial message
{assistant.initialMessage && (
  <p className="text-xs text-foreground leading-relaxed">
    {truncateText(assistant.initialMessage, 120)}
  </p>
)}

Tool Integration

Tool Count Display

{assistant.tools && assistant.tools.length > 0 && (
  <Button variant="outline" size="sm" className="h-6 px-2 text-xs">
    <Settings className="h-3 w-3 mr-1" />
    {assistant.tools.length} tool{assistant.tools.length !== 1 ? 's' : ''}
  </Button>
)}

Tool Preview Tooltip

<TooltipContent side="bottom" className="max-w-sm">
  <div className="p-2">
    <div className="text-xs font-medium mb-2">Available Tools</div>
    <CategorizedToolPreview 
      tools={assistant.tools} 
      toolConfigs={assistant.toolConfigs || {}} 
    />
  </div>
</TooltipContent>

Dependencies

  • @/lib/firebase - FirebaseService and Assistant type
  • @/components/ui/* - Avatar, Card, Badge, Button, Tooltip components
  • @/components/creator/CategorizedToolPreview - Tool categorization
  • lucide-react - Icons (ExternalLink, Settings, Loader2)

Firebase Integration

Assistant Data Structure

interface Assistant {
  name: string;
  ownerEmail: string;
  avatar?: string;
  initialMessage?: string;
  tools?: string[];
  toolConfigs?: Record<string, any>;
  initialDocuments?: any[];
  usageCount?: number;
}

Error Handling

  • Network Failures: Displays “Failed to load assistant”
  • Missing Assistant: Shows “Assistant not found”
  • Permission Issues: Handled gracefully with error message

Accessibility

Semantic Structure

  • Card Layout: Proper heading hierarchy
  • Button Labels: Clear action descriptions
  • Alt Text: Avatar images with fallback

Keyboard Navigation

  • Focusable Elements: External link button, tool tooltips
  • Tab Order: Logical navigation through interactive elements

Screen Reader Support

  • Descriptive Text: Tool counts, usage statistics
  • Tooltip Content: Additional context on hover/focus

Performance Considerations

Lazy Loading

  • On-Demand Fetching: Only fetches when assistantId provided
  • Cleanup: Proper effect cleanup prevents memory leaks
  • Caching: Relies on Firebase SDK caching mechanisms

Responsive Images

  • Avatar Optimization: Fixed size with responsive scaling
  • Fallback Rendering: Initials when avatar unavailable
  • CategorizedToolPreview - Shows organized tool information
  • SharingStatus - Displays access control information
  • QRCodeDialog - Provides sharing functionality
  • Assistant creation and management interfaces

Best Practices

  1. Provide Valid Assistant IDs: Ensure assistantId exists before rendering
  2. Handle Loading States: Always show loading feedback
  3. Graceful Errors: Display helpful error messages
  4. Responsive Usage: Consider container width constraints
  5. Accessibility: Ensure keyboard navigation and screen reader support