import { useOccupancy } from '@ably/chat/react'; import React from 'react'; import { useRoomAvatar } from '../../hooks/use-room-avatar.tsx'; import { Avatar, AvatarData } from '../atoms/avatar.tsx'; import { Button } from '../atoms/button.tsx'; import { Icon } from '../atoms/icon.tsx'; import { TypingIndicators } from './typing-indicators.tsx'; /** * Props for the RoomListItem component */ export interface RoomListItemProps { /** * Unique identifier for the room. * Used for room identification and avatar generation when no custom avatar is provided. */ roomName: string; /** * Whether this room is currently selected/active in the UI. * Controls visual highlighting and selection indicators. * When true, shows selection styling and active indicators. */ isSelected: boolean; /** * Callback function triggered when the room item is clicked. * Should handle room navigation and selection logic. * Called for clicks on the main room area (not action buttons). */ onClick: () => void; /** * Callback function triggered when the leave button is clicked. * Should handle room departure logic and UI updates. * Called only when the leave button is explicitly clicked. */ onLeave: () => void; /** * Optional custom avatar data for the room. * If not provided, uses the useRoomAvatar hook to generate/retrieve avatar data. * Allows for custom room branding and visual identity. */ avatar?: AvatarData; /** * Whether the component should render in collapsed mode (avatar only). * When true, displays only the room avatar with a selection indicator. * When false, shows full room information including name, counts, and actions. * @default false */ isCollapsed?: boolean; /** * Whether typing indicators should be displayed for this room. * Controls the visibility of real-time typing status below the room name. * @default true */ typingIndicatorsEnabled?: boolean; } /** * RoomListItem component displays a room entry in the sidebar with activity indicators and controls * * Core Features: * - Room avatar with automatic fallback to generated avatars via useRoomAvatar hook * - Activity indicators (presence count, activity status) * - Room selection with visual feedback and hover states * - Typing indicators showing who is currently typing (when enabled) * - Leave room functionality with hover-revealed action button * - Collapsed mode for compact sidebar display (avatar-only) * - Connection count display for total room occupancy (connections) * - Accessible design with proper ARIA attributes and keyboard navigation * - Theme-aware styling supporting both light and dark modes * * @example * // Basic usage in sidebar room list * setCurrentRoom("general")} * onLeave={() => leaveRoom("general")} * /> * * @example * // With custom avatar and collapsed mode * * * */ export const RoomListItem = React.memo(function RoomListItem({ roomName, isSelected, onClick, onLeave, avatar: propAvatar, isCollapsed = false, typingIndicatorsEnabled = true, }: RoomListItemProps) { // Get occupancy data const { connections, presenceMembers } = useOccupancy(); const { roomAvatar } = useRoomAvatar({ roomName }); const roomAvatarData = propAvatar || roomAvatar; /** * Checks if the room has any active users * * @returns True if at least one user is present in the room */ const isRoomActive = () => { // Check if anyone is present in the room return presenceMembers > 0; }; const isActive = isRoomActive(); // If collapsed, render just the avatar with selection indicator if (isCollapsed) { return (
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onClick(); } }} > {isSelected && (
)}
); } // Otherwise render the full room list item return (
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onClick(); } }} >
{/* Present indicator */} {isActive && (

{roomAvatarData?.displayName}

{/* Leave button - only visible on hover */} {/* Room participant count */} {connections}
{typingIndicatorsEnabled && }
); });