All files / src/web/components GroupBadgeList.tsx

100% Statements 71/71
56.25% Branches 9/16
100% Functions 3/3
100% Lines 71/71

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106  1x   1x                             1x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x   8x 1x 1x 1x 1x   8x 1x 1x 1x 1x   8x 8x 8x 8x   8x 22x 22x 22x 22x 22x 22x 22x 22x 22x 22x 22x 22x 8x   8x 1x 1x     1x 1x 1x   1x 1x 1x 1x     8x 1x 1x 1x 1x       1x 1x 1x   1x 1x   1x 1x 1x   8x   8x   1x  
import { NewsletterGroup } from '@common/types';
import { Plus } from 'lucide-react';
import React from 'react';
import GroupBadge from './GroupBadge';
 
interface GroupBadgeListProps {
  groups: NewsletterGroup[];
  activeGroupIds?: string[];
  variant?: 'default' | 'filter' | 'preview';
  size?: 'sm' | 'md' | 'lg';
  maxVisible?: number;
  onGroupClick?: (groupId: string) => void;
  onGroupRemove?: (groupId: string) => void;
  onAddGroup?: () => void;
  showAddButton?: boolean;
  className?: string;
}
 
const GroupBadgeList: React.FC<GroupBadgeListProps> = ({
  groups,
  activeGroupIds = [],
  variant = 'default',
  size = 'sm',
  maxVisible = 5,
  onGroupClick,
  onGroupRemove,
  onAddGroup,
  showAddButton = false,
  className = '',
}) => {
  const visibleGroups = groups.slice(0, maxVisible);
  const hasMore = groups.length > maxVisible;
  const remainingCount = groups.length - maxVisible;
 
  const handleGroupClick = (groupId: string) => {
    if (onGroupClick) {
      onGroupClick(groupId);
    }
  };
 
  const handleGroupRemove = (groupId: string) => {
    if (onGroupRemove) {
      onGroupRemove(groupId);
    }
  };
 
  return (
    <div
      className={`flex flex-wrap items-center gap-1 ${className}`}
      data-testid="group-badge-list"
    >
      {visibleGroups.map((group) => (
        <GroupBadge
          key={group.id}
          id={group.id}
          name={group.name}
          color={group.color}
          isActive={activeGroupIds.includes(group.id)}
          isClickable={!!onGroupClick}
          onClick={handleGroupClick}
          onRemove={variant === 'filter' ? handleGroupRemove : undefined}
          size={size}
          variant={variant}
        />
      ))}
 
      {hasMore && (
        <span
          className={`
            inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium
            bg-gray-100 text-gray-600 border border-gray-200
            ${size === 'sm' ? 'px-2 py-0.5 text-xs' : ''}
            ${size === 'md' ? 'px-3 py-1 text-sm' : ''}
            ${size === 'lg' ? 'px-4 py-1.5 text-base' : ''}
          `}
          title={`+${remainingCount} more groups`}
        >
          +{remainingCount}
        </span>
      )}
 
      {showAddButton && onAddGroup && (
        <button
          type="button"
          onClick={onAddGroup}
          className={`
            inline-flex items-center rounded-full border-2 border-dashed border-gray-300
            text-gray-500 hover:border-gray-400 hover:text-gray-600 hover:bg-gray-50
            transition-all duration-200
            ${size === 'sm' ? 'px-2 py-0.5 text-xs' : ''}
            ${size === 'md' ? 'px-3 py-1 text-sm' : ''}
            ${size === 'lg' ? 'px-4 py-1.5 text-base' : ''}
          `}
          title="Add group filter"
          data-testid="add-group-filter-button"
        >
          <Plus size={size === 'sm' ? 10 : size === 'md' ? 12 : 14} />
          <span className="ml-1">Group</span>
        </button>
      )}
    </div>
  );
};
 
export default GroupBadgeList;