import React, { useState } from "react"; import { Image, ImageSourcePropType, ImageStyle, StyleProp, StyleSheet, Text, View, ViewStyle, } from "react-native"; type AvatarSize = "xs" | "sm" | "md" | "lg" | "xl" | number; type AvatarStatus = "online" | "offline" | "busy" | "away"; interface AvatarProps { source?: ImageSourcePropType; name?: string; size?: AvatarSize; rounded?: boolean; backgroundColor?: string; textColor?: string; status?: AvatarStatus; showStatus?: boolean; style?: StyleProp; imageStyle?: StyleProp; accessibilityLabel?: string; } const SIZE_MAP: Record, number> = { xs: 24, sm: 32, md: 40, lg: 56, xl: 80, }; const STATUS_COLORS: Record = { online: "#16A34A", offline: "#9CA3AF", busy: "#DC2626", away: "#F59E0B", }; function getInitials(name?: string): string { if (!name) return "?"; const parts = name.trim().split(/\s+/); if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase(); return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase(); } const Avatar: React.FC = ({ source, name, size = "md", rounded = true, backgroundColor = "#E5E7EB", textColor = "#374151", status, showStatus = false, style, imageStyle, accessibilityLabel, }) => { const [errored, setErrored] = useState(false); const dim = typeof size === "number" ? size : SIZE_MAP[size]; const radius = rounded ? dim / 2 : dim * 0.15; const fontSize = Math.max(10, dim * 0.4); const showImage = source && !errored; return ( {showImage ? ( setErrored(true)} style={[ { width: dim, height: dim, borderRadius: radius }, imageStyle, ]} resizeMode="cover" /> ) : ( {getInitials(name)} )} {showStatus && status && ( )} ); }; const styles = StyleSheet.create({ container: { alignItems: "center", justifyContent: "center", overflow: "hidden", }, statusDot: { position: "absolute", bottom: 0, right: 0, borderWidth: 2, borderColor: "#FFFFFF", }, }); export default Avatar;