import React, { useState } from 'react'; import { Image, PixelRatio, StyleProp, StyleSheet, View, ViewStyle } from 'react-native'; import { useTheme } from '../../contexts/themeContext/ThemeContext'; const randomImageBaseUrl = 'https://getstream.io/random_png/'; const randomSvgBaseUrl = 'https://getstream.io/random_svg/'; const streamCDN = 'stream-io-cdn.com'; const styles = StyleSheet.create({ container: { overflow: 'hidden', }, flex: { flex: 1 }, }); const getInitials = (fullName: string) => fullName .split(' ') .slice(0, 2) .map((name) => name.charAt(0)) .join(' '); export type GroupAvatarProps = { /** total size in pixels */ size: number; containerStyle?: StyleProp; /** image urls */ images?: string[]; /** name of the users, used for fallback */ names?: string[]; testID?: string; }; /** * GroupAvatar - A round group of avatar images with fallbacks to users' initials */ export const GroupAvatar: React.FC = (props) => { const { containerStyle, images, names, size, testID } = props; const { theme: { groupAvatar: { container, image }, }, } = useTheme(); const [imageError, setImageError] = useState(false); /** * [ * [ * { height: number; name: string; url: string; width: number }, * { height: number; name: string; url: string; width: number }, * ], * [ * { height: number; name: string; url: string; width: number }, * { height: number; name: string; url: string; width: number }, * ], * ] */ const imagesOrNames = images || names || []; const avatarImages = imagesOrNames.slice(0, 4).reduce((returnArray, currentImage, index) => { const url = currentImage.startsWith('http') ? currentImage : `${randomImageBaseUrl}${ names ? `?name=${getInitials(names[index])}&size=${ imagesOrNames.length <= 2 ? size : size / 2 }` : '' }`; if (imagesOrNames.length <= 2) { Image.prefetch( imageError ? url : url.replace( 'h=%2A', `h=${PixelRatio.getPixelSizeForLayoutSize( imagesOrNames.length <= 2 ? size : size / 2, )}`, ), ).catch(() => { // do nothing, not a big deal that prefetch failed }); returnArray[0] = [ ...(returnArray[0] || []), { height: imagesOrNames.length === 1 ? size : size / 2, name: names ? names[index] : '', url, width: size, }, ]; } else { Image.prefetch( imageError ? url : url.replace('h=%2A', `h=${PixelRatio.getPixelSizeForLayoutSize(size / 2)}`), )?.catch(() => { // do nothing, not a big deal that prefetch failed }); if (index < 2) { returnArray[0] = [ ...(returnArray[0] || []), { height: size / 2, name: names ? names[index] : '', url, width: size / 2, }, ]; } else { returnArray[1] = [ ...(returnArray[1] || []), { height: size / 2, name: names ? names[index] : '', url, width: imagesOrNames.length === 3 ? size : size / 2, }, ]; } } return returnArray; }, [] as { height: number; name: string; url: string; width: number }[][]); return ( {avatarImages.map((column, colIndex) => ( {column.map(({ height, name, url, width }, rowIndex) => ( setImageError(true)} source={{ uri: imageError || url.includes(randomSvgBaseUrl) ? url.includes(streamCDN) ? url : `${randomImageBaseUrl}${ name ? `?name=${getInitials(name)}&size=${height}` : '' }` : url.replace('h=%2A', `h=${PixelRatio.getPixelSizeForLayoutSize(height)}`), }} style={[ image, size ? { height, width, } : {}, ]} testID={`group-avatar-image-${colIndex}-${rowIndex}`} /> ))} ))} ); }; GroupAvatar.displayName = 'GroupAvatar{groupAvatar}';