1- import React from 'react' ;
1+ import React , { useMemo , useState } from 'react' ;
22import PropTypes from 'prop-types' ;
33
44import styled from '@stream-io/styled-components' ;
@@ -8,100 +8,89 @@ const BASE_AVATAR_FALLBACK_TEXT_SIZE = 14;
88const BASE_AVATAR_SIZE = 32 ;
99
1010const AvatarContainer = styled . View `
11- display: flex;
1211 align-items: center;
1312 ${ ( { theme } ) => theme . avatar . container . css }
1413` ;
1514
1615const AvatarImage = styled . Image `
17- border-radius: ${ ( { size } ) => size / 2 } ;
18- width : ${ ( { size } ) => size } ;
19- height : ${ ( { size } ) => size } ;
16+ border-radius: ${ ( { size } ) => size / 2 } px ;
17+ height : ${ ( { size } ) => size } px ;
18+ width : ${ ( { size } ) => size } px ;
2019 ${ ( { theme } ) => theme . avatar . image . css }
2120` ;
2221
2322const AvatarFallback = styled . View `
24- border-radius: ${ ( { size } ) => size / 2 } ;
25- width: ${ ( { size } ) => size } ;
26- height: ${ ( { size } ) => size } ;
23+ align-items: center;
2724 background-color: ${ ( { theme } ) => theme . colors . primary } ;
25+ border-radius: ${ ( { size } ) => size / 2 } px;
26+ height: ${ ( { size } ) => size } px;
2827 justify-content: center;
29- align-items: center ;
28+ width: ${ ( { size } ) => size } px ;
3029 ${ ( { theme } ) => theme . avatar . fallback . css }
3130` ;
3231
3332const AvatarText = styled . Text `
3433 color: ${ ( { theme } ) => theme . colors . textLight } ;
35- text-transform: uppercase;
36- font-size: ${ ( { fontSize } ) => fontSize } ;
34+ font-size: ${ ( { fontSize } ) => fontSize } px;
3735 font-weight: bold;
36+ text-transform: uppercase;
3837 ${ ( { theme } ) => theme . avatar . text . css }
3938` ;
4039
40+ const getInitials = ( fullName ) =>
41+ fullName
42+ ? fullName
43+ . split ( ' ' )
44+ . slice ( 0 , 2 )
45+ . map ( ( name ) => name . charAt ( 0 ) )
46+ : null ;
47+
4148/**
4249 * Avatar - A round avatar image with fallback to user's initials
4350 *
4451 * @example ../docs/Avatar.md
45- * @extends PureComponent
4652 */
47- class Avatar extends React . PureComponent {
48- static themePath = 'avatar' ;
49- static propTypes = {
50- /** image url */
51- image : PropTypes . string ,
52- /** name of the picture, used for title tag fallback */
53- name : PropTypes . string ,
54- /** size in pixels */
55- size : PropTypes . number ,
56- /** Style overrides */
57- style : PropTypes . object ,
58- } ;
59-
60- static defaultProps = {
61- size : 32 ,
62- } ;
63-
64- state = {
65- imageError : false ,
66- } ;
53+ const Avatar = ( { image, name, size = BASE_AVATAR_SIZE } ) => {
54+ const [ imageError , setImageError ] = useState ( false ) ;
6755
68- setError = ( ) => {
69- this . setState ( {
70- imageError : true ,
71- } ) ;
72- } ;
56+ const fontSize = useMemo (
57+ ( ) => BASE_AVATAR_FALLBACK_TEXT_SIZE * ( size / BASE_AVATAR_SIZE ) ,
58+ [ size ] ,
59+ ) ;
60+ const initials = useMemo ( ( ) => getInitials ( name ) , [ name ] ) ;
7361
74- getInitials = ( name ) =>
75- name
76- ? name
77- . split ( ' ' )
78- . slice ( 0 , 2 )
79- . map ( ( name ) => name . charAt ( 0 ) )
80- : null ;
62+ return (
63+ < AvatarContainer >
64+ { image && ! imageError ? (
65+ < AvatarImage
66+ accessibilityLabel = 'initials'
67+ onError = { ( ) => setImageError ( true ) }
68+ resizeMethod = 'resize'
69+ size = { size }
70+ source = { { uri : image } }
71+ testID = 'avatar-image'
72+ />
73+ ) : (
74+ < AvatarFallback size = { size } >
75+ < AvatarText fontSize = { fontSize } testID = 'avatar-text' >
76+ { initials }
77+ </ AvatarText >
78+ </ AvatarFallback >
79+ ) }
80+ </ AvatarContainer >
81+ ) ;
82+ } ;
8183
82- render ( ) {
83- const { size, name, image } = this . props ;
84- const initials = this . getInitials ( name ) ;
85- const fontSize = BASE_AVATAR_FALLBACK_TEXT_SIZE * ( size / BASE_AVATAR_SIZE ) ;
84+ Avatar . propTypes = {
85+ /** image url */
86+ image : PropTypes . string ,
87+ /** name of the picture, used for title tag fallback */
88+ name : PropTypes . string ,
89+ /** size in pixels */
90+ size : PropTypes . number ,
91+ } ;
8692
87- return (
88- < AvatarContainer >
89- { image && ! this . state . imageError ? (
90- < AvatarImage
91- size = { size }
92- source = { { uri : image } }
93- accessibilityLabel = "initials"
94- resizeMethod = "resize"
95- onError = { this . setError }
96- />
97- ) : (
98- < AvatarFallback size = { size } >
99- < AvatarText fontSize = { fontSize } > { initials } </ AvatarText >
100- </ AvatarFallback >
101- ) }
102- </ AvatarContainer >
103- ) ;
104- }
105- }
93+ Avatar . themePath = 'avatar' ;
10694
95+ // TODO: remove HOC and use a theme context provider
10796export default themed ( Avatar ) ;
0 commit comments