您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

Notification.tsx 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import React, { useCallback, useContext, useEffect, useRef } from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import { Animated, Text, TextStyle, View, ViewStyle } from 'react-native';
  4. import Icon from '../../../base/icons/components/Icon';
  5. import {
  6. IconCloseLarge,
  7. IconInfoCircle,
  8. IconUsers,
  9. IconWarning
  10. } from '../../../base/icons/svg';
  11. import { colors } from '../../../base/ui/Tokens';
  12. import BaseTheme from '../../../base/ui/components/BaseTheme.native';
  13. import Button from '../../../base/ui/components/native/Button';
  14. import IconButton from '../../../base/ui/components/native/IconButton';
  15. import { BUTTON_MODES, BUTTON_TYPES } from '../../../base/ui/constants.native';
  16. import { replaceNonUnicodeEmojis } from '../../../chat/functions';
  17. import { NOTIFICATION_ICON, NOTIFICATION_TYPE } from '../../constants';
  18. import { INotificationProps } from '../../types';
  19. import { NotificationsTransitionContext } from '../NotificationsTransition';
  20. import styles from './styles';
  21. /**
  22. * Secondary colors for notification icons.
  23. *
  24. * @type {{error, info, normal, success, warning}}
  25. */
  26. const ICON_COLOR = {
  27. error: colors.error06,
  28. normal: colors.primary06,
  29. success: colors.success05,
  30. warning: colors.warning05
  31. };
  32. export interface IProps extends INotificationProps {
  33. _participants: ArrayLike<any>;
  34. onDismissed: Function;
  35. }
  36. const Notification = ({
  37. appearance = NOTIFICATION_TYPE.NORMAL,
  38. customActionHandler,
  39. customActionNameKey,
  40. customActionType,
  41. description,
  42. descriptionArguments,
  43. descriptionKey,
  44. icon,
  45. onDismissed,
  46. title,
  47. titleArguments,
  48. titleKey,
  49. uid
  50. }: IProps) => {
  51. const { t } = useTranslation();
  52. const notificationOpacityAnimation = useRef(new Animated.Value(0)).current;
  53. const { unmounting } = useContext(NotificationsTransitionContext);
  54. useEffect(() => {
  55. Animated.timing(
  56. notificationOpacityAnimation,
  57. {
  58. toValue: 1,
  59. duration: 200,
  60. useNativeDriver: true
  61. })
  62. .start();
  63. }, []);
  64. useEffect(() => {
  65. if (unmounting.get(uid ?? '')) {
  66. Animated.timing(
  67. notificationOpacityAnimation,
  68. {
  69. toValue: 0,
  70. duration: 200,
  71. useNativeDriver: true
  72. })
  73. .start();
  74. }
  75. }, [ unmounting ]);
  76. const onDismiss = useCallback(() => {
  77. onDismissed(uid);
  78. }, [ onDismissed, uid ]);
  79. const mapAppearanceToButtons = () => {
  80. if (customActionNameKey?.length && customActionHandler?.length && customActionType?.length) {
  81. return customActionNameKey?.map((customAction: string, index: number) => (
  82. <Button
  83. accessibilityLabel = { customAction }
  84. key = { index }
  85. labelKey = { customAction }
  86. mode = { BUTTON_MODES.TEXT }
  87. // eslint-disable-next-line react/jsx-no-bind
  88. onClick = { () => {
  89. if (customActionHandler[index]()) {
  90. onDismiss();
  91. }
  92. } }
  93. style = { styles.btn }
  94. // @ts-ignore
  95. type = { customActionType[index] } />
  96. ));
  97. }
  98. return [];
  99. };
  100. const getIcon = () => {
  101. let src;
  102. switch (icon || appearance) {
  103. case NOTIFICATION_ICON.PARTICIPANT:
  104. src = IconInfoCircle;
  105. break;
  106. case NOTIFICATION_ICON.PARTICIPANTS:
  107. src = IconUsers;
  108. break;
  109. case NOTIFICATION_ICON.WARNING:
  110. src = IconWarning;
  111. break;
  112. default:
  113. src = IconInfoCircle;
  114. break;
  115. }
  116. return src;
  117. };
  118. const _getDescription = () => {
  119. const descriptionArray = [];
  120. descriptionKey
  121. && descriptionArray.push(t(descriptionKey, descriptionArguments));
  122. description && descriptionArray.push(description);
  123. return descriptionArray;
  124. };
  125. // eslint-disable-next-line react/no-multi-comp
  126. const _renderContent = () => {
  127. const titleText = title || (titleKey && t(titleKey, titleArguments));
  128. const descriptionArray = _getDescription();
  129. if (descriptionArray?.length) {
  130. return (
  131. <>
  132. <Text style = { styles.contentTextTitle as TextStyle }>
  133. {titleText}
  134. </Text>
  135. {
  136. descriptionArray.map((line, index) => (
  137. <Text
  138. key = { index }
  139. style = { styles.contentText }>
  140. {replaceNonUnicodeEmojis(line)}
  141. </Text>
  142. ))
  143. }
  144. </>
  145. );
  146. }
  147. return (
  148. <Text style = { styles.contentTextTitle as TextStyle }>
  149. {titleText}
  150. </Text>
  151. );
  152. };
  153. return (
  154. <Animated.View
  155. pointerEvents = 'box-none'
  156. style = { [
  157. _getDescription()?.length
  158. ? styles.notificationWithDescription
  159. : styles.notification,
  160. {
  161. opacity: notificationOpacityAnimation
  162. }
  163. ] as ViewStyle[] }>
  164. <View
  165. style = { (icon === NOTIFICATION_ICON.PARTICIPANTS
  166. ? styles.contentColumn
  167. : styles.interactiveContentColumn) as ViewStyle }>
  168. <View style = { styles.iconContainer as ViewStyle }>
  169. <Icon
  170. color = { ICON_COLOR[appearance as keyof typeof ICON_COLOR] }
  171. size = { 24 }
  172. src = { getIcon() } />
  173. </View>
  174. <View
  175. pointerEvents = 'box-none'
  176. style = { styles.contentContainer }>
  177. {_renderContent()}
  178. </View>
  179. <View style = { styles.btnContainer as ViewStyle }>
  180. {mapAppearanceToButtons()}
  181. </View>
  182. </View>
  183. <IconButton
  184. color = { BaseTheme.palette.icon04 }
  185. onPress = { onDismiss }
  186. src = { IconCloseLarge }
  187. type = { BUTTON_TYPES.TERTIARY } />
  188. </Animated.View>
  189. );
  190. };
  191. export default Notification;