Emissary List Compact Component

The EmissaryListCompact component (src/components/EmissaryListCompact.tsx) provides a compact list view of AI assistants (emissaries) with their last message previews and relative timestamps.

Overview

This component displays a list of AI assistants in a compact format, showing each assistant’s avatar, name, last message, and timestamp. It includes Firebase integration to fetch recent messages and provides navigation to individual assistant pages.

Key Features

Message Integration

  • Fetches the most recent message for each assistant
  • Displays message previews with intelligent truncation
  • Shows relative timestamps using the RelativeTime component
  • Sorts assistants by last message activity

Interactive Interface

  • Click any assistant to navigate to their chat page
  • Hover effects for better user experience
  • Loading states during data fetching
  • Graceful handling of assistants with no messages

Visual Design

  • Avatar display with fallback initials
  • Compact card layout with borders and spacing
  • Responsive text truncation
  • Clear visual hierarchy

Props Interface

interface EmissaryListCompactProps {
  bots: AssistantDisplay[];
  currentUser?: any;
  onView?: (bot: AssistantDisplay) => void;
}

Data Types

interface BotWithMessage extends AssistantDisplay {
  lastMessage?: string;
  lastMessageTime?: Date;
}

Implementation Example

// Basic usage with navigation
<EmissaryListCompact 
  bots={assistantList}
  currentUser={currentUser}
/>

// With custom view handler
<EmissaryListCompact 
  bots={assistantList}
  currentUser={currentUser}
  onView={(bot) => {
    // Custom navigation or modal opening
    openAssistantModal(bot);
  }}
/>

Key Functionality

Message Fetching

The component automatically fetches the latest message for each assistant:

const fetchLastMessages = async () => {
  const updatedBots: BotWithMessage[] = [];

  for (const bot of bots) {
    try {
      // Fetch most recent message using FirebaseService
      const messages = await FirebaseService.getMessages(bot.assistantId, 1);
      
      if (messages && messages.length > 0) {
        const lastMsg = messages[messages.length - 1];
        lastMessage = lastMsg.content || '';
        lastMessageTime = lastMsg.timestamp ? new Date(lastMsg.timestamp) : lastMessageTime;
      }
    } catch (error) {
      console.error(`Error fetching messages for bot ${bot.assistantId}:`, error);
    }

    updatedBots.push({
      ...bot,
      lastMessage,
      lastMessageTime
    });
  }

  // Sort by most recent activity
  updatedBots.sort((a, b) => (b.lastMessageTime?.getTime() || 0) - (a.lastMessageTime?.getTime() || 0));
  setBotsWithMessages(updatedBots);
};

Message Truncation

Intelligent text truncation for long messages:

const truncateMessage = (message: string, maxWords: number = 30): string => {
  const words = message.split(' ');
  if (words.length <= maxWords) return message;
  return words.slice(0, maxWords).join(' ') + '...';
};

Flexible navigation with custom or default behavior:

const handleView = (bot: AssistantDisplay) => {
  if (onView) {
    onView(bot);  // Custom handler
  } else {
    router.push(`/assistant/${bot.assistantId}`);  // Default navigation
  }
};

UI Structure

Each assistant is displayed in a consistent card format:

<div className="flex items-center space-x-3 p-4 hover:bg-muted/50 transition-colors cursor-pointer rounded-lg border border-border">
  <Avatar className="h-12 w-12">
    <AvatarImage src={bot.avatar} alt={bot.name} />
    <AvatarFallback>{bot.name?.[0] || '?'}</AvatarFallback>
  </Avatar>
  
  <div className="flex-1 min-w-0">
    <div className="flex items-center justify-between">
      <h3 className="font-medium truncate text-base">{bot.name}</h3>
      {bot.lastMessageTime && (
        <span className="text-xs text-muted-foreground">
          <RelativeTime date={bot.lastMessageTime} />
        </span>
      )}
    </div>
    {bot.lastMessage ? (
      <p className="text-muted-foreground text-sm line-clamp-2">
        {truncateMessage(bot.lastMessage)}
      </p>
    ) : (
      <p className="text-muted-foreground text-sm italic">No messages yet</p>
    )}
  </div>
  
  <ChevronRight className="h-4 w-4 text-muted-foreground" />
</div>

Dependencies

  • @/types - AssistantDisplay type definition
  • @/components/ui/avatar - Avatar component with fallback
  • @/components/RelativeTime - Timestamp formatting
  • @/lib/firebase - Firebase service for message fetching
  • next/navigation - Router for navigation
  • lucide-react - ChevronRight icon

State Management

The component manages several states:

  • botsWithMessages - Enhanced bot data with message information
  • loading - Loading state during message fetching
  • Firebase authentication state monitoring

Loading States

Displays a loading spinner while fetching messages:

if (loading) {
  return (
    <div className="flex items-center justify-center p-8">
      <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
    </div>
  );
}

Error Handling

  • Graceful handling of message fetch failures
  • Fallback to assistant creation date when no messages exist
  • Console logging for debugging purposes
  • No UI disruption on individual assistant errors

Performance Considerations

  • Fetches only the most recent message (limit: 1) for each assistant
  • Implements proper async/await patterns
  • Includes small delays to ensure Firebase initialization
  • Sorts results to show most active assistants first

Integration Notes

This component is typically used in:

  • Assistant selection interfaces
  • Dashboard views showing assistant activity
  • Mobile-friendly list layouts

It requires proper Firebase authentication and integrates with the overall assistant management system in the application.