All files / src/components/shared UserAvatar.tsx

88.88% Statements 24/27
58.13% Branches 25/43
100% Functions 3/3
100% Lines 23/23

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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147                                                                              7x 70x 68x 68x 68x 68x     2x 2x 70x 70x       7x 70x 70x 1059x   70x 70x     7x                           70x     70x     70x     70x                           70x                                                                                   70x        
/**
 * UserAvatar Component
 *
 * Shared component for displaying user avatar with name and optional company.
 * Used across UserManagement and EventManagement components.
 *
 * Features:
 * - Avatar with initials fallback
 * - Consistent color generation from name
 * - Optional company display
 * - Configurable sizes
 * - Tooltip support
 */
 
import React from 'react';
import { Avatar, Box, Typography, Tooltip, Stack } from '@mui/material';
 
interface UserAvatarProps {
  /** User's full name or firstName/lastName separately */
  name?: string;
  firstName?: string;
  lastName?: string;
  /** Company name (optional) */
  company?: string;
  /** Profile picture URL (optional) */
  profilePictureUrl?: string;
  /** Avatar size in pixels (default: 40) */
  size?: number;
  /** Show company below name (default: true if company provided) */
  showCompany?: boolean;
  /** Use horizontal layout (avatar + text side-by-side) (default: true) */
  horizontal?: boolean;
  /** Show tooltip with full name (default: false) */
  showTooltip?: boolean;
  /** Custom background color (optional - will generate from name if not provided) */
  bgcolor?: string;
}
 
// Helper function to generate initials from name
const getInitials = (firstName?: string, lastName?: string, fullName?: string): string => {
  if (fullName) {
    const parts = fullName.trim().split(' ');
    Iif (parts.length === 0) return '?';
    Iif (parts.length === 1) return parts[0].charAt(0).toUpperCase();
    return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase();
  }
 
  Iif (!firstName && !lastName) return '?';
  const first = firstName?.charAt(0).toUpperCase() || '';
  const last = lastName?.charAt(0).toUpperCase() || '';
  return `${first}${last}`;
};
 
// Helper function to generate consistent avatar color from name
const stringToColor = (str: string): string => {
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    hash = str.charCodeAt(i) + ((hash << 5) - hash);
  }
  const hue = hash % 360;
  return `hsl(${hue}, 60%, 50%)`;
};
 
export const UserAvatar: React.FC<UserAvatarProps> = ({
  name,
  firstName,
  lastName,
  company,
  profilePictureUrl,
  size = 40,
  showCompany = !!company,
  horizontal = true,
  showTooltip = false,
  bgcolor,
}) => {
  // Determine full name
  const fullName =
    name || (firstName && lastName ? `${firstName} ${lastName}` : firstName || lastName || '');
 
  // Generate initials (fallback to '?' if no name)
  const initials = getInitials(firstName, lastName, name);
 
  // Generate background color if not provided (use '?' if no name for consistent color)
  const avatarBgColor = bgcolor || stringToColor(fullName || '?');
 
  const avatarElement = (
    <Avatar
      src={profilePictureUrl}
      alt={fullName}
      sx={{
        bgcolor: avatarBgColor,
        width: size,
        height: size,
        fontSize: size * 0.4,
      }}
    >
      {initials}
    </Avatar>
  );
 
  const content = horizontal ? (
    <Stack direction="row" spacing={2} alignItems="center">
      {showTooltip ? (
        <Tooltip title={fullName} arrow>
          {avatarElement}
        </Tooltip>
      ) : (
        avatarElement
      )}
      <Box sx={{ display: 'flex', flexDirection: 'column' }}>
        <Typography variant="body2" fontWeight="medium">
          {fullName}
        </Typography>
        {showCompany && company && (
          <Typography variant="caption" color="text.secondary">
            {company}
          </Typography>
        )}
      </Box>
    </Stack>
  ) : (
    <Stack direction="column" spacing={1} alignItems="center">
      {showTooltip ? (
        <Tooltip title={fullName} arrow>
          {avatarElement}
        </Tooltip>
      ) : (
        avatarElement
      )}
      <Box textAlign="center">
        <Typography variant="body2" fontWeight="medium">
          {fullName}
        </Typography>
        {showCompany && company && (
          <Typography variant="caption" color="text.secondary">
            {company}
          </Typography>
        )}
      </Box>
    </Stack>
  );
 
  return content;
};
 
export default UserAvatar;