index.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. import {
  2. useState
  3. } from "react";
  4. import {
  5. TouchableOpacity,
  6. Image,
  7. View
  8. } from "react-native";
  9. import type IAvatarProps from "./type";
  10. import stylesheet, {
  11. getAvatarSize,
  12. useStyles
  13. } from "./stylesheet";
  14. import {
  15. NCoreUIKitTheme
  16. } from "../../core/hooks";
  17. import {
  18. UserRound as UserRoundIcon
  19. } from "lucide-react-native";
  20. import Loading from "../loading";
  21. import Text from "../text";
  22. const Avatar = ({
  23. titleAbbreviationType = "first-last",
  24. isShowStatusIndicatorSplicer = true,
  25. avatarBackgroundColor = "default",
  26. statusIndicatorType = "online",
  27. titleColor = "onPrimary",
  28. isShowBorder = false,
  29. isStatusIndicator,
  30. isWorkWithAction,
  31. image: ImageProp,
  32. backgroundColor,
  33. size = "medium",
  34. icon: IconProp,
  35. imageSource,
  36. customTheme,
  37. borderColor,
  38. isDisabled,
  39. imageProps,
  40. isLoading,
  41. iconColor,
  42. imageUrl,
  43. onPress,
  44. title,
  45. style
  46. }: IAvatarProps) => {
  47. const {
  48. borders,
  49. colors,
  50. spaces
  51. } = NCoreUIKitTheme.useContext(customTheme);
  52. const currentSize = getAvatarSize({
  53. spaces,
  54. size
  55. });
  56. const [
  57. imageLoadError,
  58. setImageLoadError
  59. ] = useState(false);
  60. const {
  61. statusIndicator: statusIndicatorDynamicStyle,
  62. container: containerDynamicStyle,
  63. image: imageDynamicStyle,
  64. icon: iconDynamicStyle
  65. } = useStyles({
  66. isShowStatusIndicatorSplicer,
  67. avatarBackgroundColor,
  68. statusIndicatorType,
  69. image: ImageProp,
  70. backgroundColor,
  71. isShowBorder,
  72. borderColor,
  73. currentSize,
  74. isDisabled,
  75. isLoading,
  76. imageUrl,
  77. borders,
  78. colors,
  79. title
  80. });
  81. const calculateShortTitle = () => {
  82. if(!title) {
  83. return "";
  84. }
  85. const allWords: Array<string> = title.split(" ");
  86. if(titleAbbreviationType === "every-first") {
  87. let newString = "";
  88. allWords.forEach((wordItem, wordIndex) => {
  89. if(wordIndex < 3) newString += wordItem[0];
  90. });
  91. return newString;
  92. }
  93. if(titleAbbreviationType === "first-last") {
  94. let newString = "";
  95. if(allWords[0]) newString += allWords[0][0];
  96. if(allWords.length > 1 && allWords[allWords.length - 1]) newString += allWords[allWords.length - 1]?.[0];
  97. return newString;
  98. }
  99. if(titleAbbreviationType === "first-next") {
  100. let newString = "";
  101. if(allWords[0]) newString += allWords[0][0];
  102. if(allWords[1]) newString += allWords[1][0];
  103. return newString;
  104. }
  105. return title;
  106. };
  107. const renderIcon = () => {
  108. if(IconProp) {
  109. return <IconProp
  110. size={currentSize.iconSize}
  111. customColor={iconColor}
  112. color="default"
  113. style={{
  114. ...iconDynamicStyle
  115. }}
  116. />;
  117. }
  118. return <UserRoundIcon
  119. color={iconColor ? iconColor : colors.content.icon.default}
  120. size={currentSize.iconSize}
  121. style={{
  122. ...iconDynamicStyle
  123. }}
  124. />;
  125. };
  126. const renderStatusIndicator = () => {
  127. if(!isStatusIndicator) {
  128. return null;
  129. }
  130. return <View
  131. style={[
  132. stylesheet.statusIndicator,
  133. statusIndicatorDynamicStyle
  134. ]}
  135. />;
  136. };
  137. const renderLoading = () => {
  138. let loadingColor: keyof NCoreUIKit.IconContentColors = "default";
  139. if(title) {
  140. loadingColor = "onPrimary";
  141. } else if(imageUrl || ImageProp) {
  142. loadingColor = "mid";
  143. }
  144. return <Loading
  145. color={loadingColor}
  146. />;
  147. };
  148. const renderContent = () => {
  149. if(isLoading) {
  150. return renderLoading();
  151. }
  152. if(IconProp) {
  153. return renderIcon();
  154. }
  155. if(!title && !ImageProp && !imageUrl) {
  156. return renderIcon();
  157. }
  158. if((imageUrl || ImageProp) && imageLoadError) {
  159. if(title) {
  160. return <Text
  161. variant={currentSize.fontSize}
  162. color={titleColor}
  163. >
  164. {calculateShortTitle()}
  165. </Text>;
  166. } else {
  167. return renderIcon();
  168. }
  169. }
  170. if(ImageProp) {
  171. return <ImageProp
  172. {...imageProps}
  173. onError={() => setImageLoadError(true)}
  174. height={currentSize.size}
  175. width={currentSize.size}
  176. style={[
  177. stylesheet.image,
  178. imageDynamicStyle,
  179. imageProps?.style
  180. ]}
  181. />;
  182. }
  183. if(imageUrl) {
  184. return <Image
  185. {...imageProps}
  186. onError={() => setImageLoadError(true)}
  187. height={currentSize.size}
  188. width={currentSize.size}
  189. source={{
  190. uri: imageUrl,
  191. ...imageSource
  192. }}
  193. style={[
  194. stylesheet.image,
  195. imageDynamicStyle,
  196. imageProps?.style
  197. ]}
  198. />;
  199. }
  200. return <Text
  201. variant={currentSize.fontSize}
  202. color={titleColor}
  203. >
  204. {calculateShortTitle()}
  205. </Text>;
  206. };
  207. return <TouchableOpacity
  208. disabled={!isWorkWithAction || isDisabled || isLoading}
  209. onPress={!isWorkWithAction || isDisabled || isLoading ? undefined : () => {
  210. if(onPress) onPress();
  211. }}
  212. style={[
  213. style,
  214. stylesheet.container,
  215. containerDynamicStyle
  216. ]}
  217. >
  218. {renderContent()}
  219. {renderStatusIndicator()}
  220. </TouchableOpacity>;
  221. };
  222. export default Avatar;