Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

Notification.tsx 6.8KB

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