// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import { InteractionManager, Platform, StyleSheet, TouchableOpacity, Text, View, } from 'react-native'; import FastImage from 'react-native-fast-image'; import {Navigation} from 'react-native-navigation'; import * as Animatable from 'react-native-animatable'; import {PanGestureHandler} from 'react-native-gesture-handler'; import {Client4} from '@mm-redux/client'; import {isDirectChannel} from '@mm-redux/utils/channel_utils'; import EventEmitter from '@mm-redux/utils/event_emitter'; import {displayUsername} from '@mm-redux/utils/user_utils'; import {popToRoot, dismissAllModals, dismissOverlay} from 'app/actions/navigation'; import FormattedText from 'app/components/formatted_text'; import ProfilePicture from 'app/components/profile_picture'; import {NavigationTypes} from 'app/constants'; import {changeOpacity} from 'app/utils/theme'; import logo from 'assets/images/icon.png'; import webhookIcon from 'assets/images/icons/webhook.jpg'; const IMAGE_SIZE = 33; const AUTO_DISMISS_TIME_MILLIS = 5000; export default class Notification extends PureComponent { static propTypes = { actions: PropTypes.shape({ loadFromPushNotification: PropTypes.func.isRequired, }).isRequired, componentId: PropTypes.string.isRequired, channel: PropTypes.object, config: PropTypes.object, notification: PropTypes.object.isRequired, teammateNameDisplay: PropTypes.string, user: PropTypes.object, }; state = { keyFrames: { from: { translateY: -100, }, to: { translateY: 0, }, }, } tapped = false; componentDidMount() { this.setDismissTimer(); this.setDidDisappearListener(); this.setShowOverlayListener(); } componentWillUnmount() { this.clearDismissTimer(); this.clearDidDisappearListener(); this.clearShowOverlayListener(); } setDismissTimer = () => { this.dismissTimer = setTimeout(() => { if (!this.tapped) { this.animateDismissOverlay(); } }, AUTO_DISMISS_TIME_MILLIS); } clearDismissTimer = () => { if (this.dismissTimer) { clearTimeout(this.dismissTimer); this.dismissTimer = null; } } setDidDisappearListener = () => { this.didDismissListener = Navigation.events().registerComponentDidDisappearListener(async ({componentId}) => { if (componentId === this.props.componentId && this.tapped) { await dismissAllModals(); await popToRoot(); } }); } clearDidDisappearListener = () => { this.didDismissListener.remove(); } setShowOverlayListener = () => { EventEmitter.on(NavigationTypes.NAVIGATION_SHOW_OVERLAY, this.onNewOverlay); } clearShowOverlayListener = () => { EventEmitter.off(NavigationTypes.NAVIGATION_SHOW_OVERLAY, this.onNewOverlay); } onNewOverlay = () => { // Dismiss this overlay so that there is only ever one. this.dismissOverlay(); } dismissOverlay = () => { this.clearDismissTimer(); const {componentId} = this.props; dismissOverlay(componentId); } animateDismissOverlay = () => { this.clearDismissTimer(); this.setState({ keyFrames: { from: { translateY: 0, }, to: { translateY: -100, }, }, }); setTimeout(() => this.dismissOverlay(), 1000); } notificationTapped = () => { this.tapped = true; this.clearDismissTimer(); const {actions, notification} = this.props; EventEmitter.emit(NavigationTypes.CLOSE_MAIN_SIDEABR); EventEmitter.emit(NavigationTypes.CLOSE_SETTINGS_SIDEBAR); this.dismissOverlay(); InteractionManager.runAfterInteractions(() => { if (!notification.localNotification) { actions.loadFromPushNotification(notification); } }); }; getNotificationIcon = () => { const {config, notification, user} = this.props; const {data} = notification; let icon = ( ); if (data.from_webhook && config.EnablePostIconOverride === 'true' && data.use_user_icon !== 'true') { const overrideIconURL = Client4.getAbsoluteUrl(data.override_icon_url); // eslint-disable-line camelcase const wsIcon = data.override_icon_url ? {uri: overrideIconURL} : webhookIcon; icon = ( ); } else if (user) { icon = ( ); } return icon; }; getNotificationTitle = (notification) => { const {channel} = this.props; const {message, data} = notification; if (data.version === 'v2') { if (data.channel_name) { return ( {data.channel_name} ); } return null; } const msg = message.split(':'); const titleText = msg.shift(); let title = ( {titleText} ); const userName = this.getNotificationUserName(); if (userName && channel) { let channelName; let inText; if (!isDirectChannel(channel)) { inText = ( ); channelName = ( {channel.display_name} ); } title = ( {userName} {inText} {channelName} ); } return title; }; getNotificationUserName = () => { const {config, notification, teammateNameDisplay, user} = this.props; const {data} = notification; let userName; if (data.override_username && config.EnablePostUsernameOverride === 'true') { userName = ( {data.override_username} ); } else if (user) { userName = ( {displayUsername(user, teammateNameDisplay)} ); } return userName; }; render() { const {notification} = this.props; const {data, message} = notification; if (message) { let messageText; if (data.version !== 'v2') { const msg = message.split(':'); messageText = msg.join('').trim(); } else if (Platform.OS === 'ios') { messageText = message.body || message; } else { messageText = message; } const title = this.getNotificationTitle(notification); const icon = this.getNotificationIcon(); return ( {icon} {title} {messageText} ); } return null; } } const style = StyleSheet.create({ container: { alignItems: 'flex-start', backgroundColor: changeOpacity('#000', 1), flexDirection: 'row', justifyContent: 'flex-start', paddingHorizontal: 10, width: '100%', ...Platform.select({ android: { height: 68, }, ios: { height: 88, }, }), }, iconContainer: { ...Platform.select({ android: { paddingTop: 17, }, ios: { paddingTop: 37, }, }), }, icon: { borderRadius: (IMAGE_SIZE / 2), height: IMAGE_SIZE, width: IMAGE_SIZE, }, textContainer: { flex: 1, flexDirection: 'column', alignSelf: 'stretch', alignItems: 'flex-start', marginLeft: 10, ...Platform.select({ android: { marginTop: 17, height: 50, }, ios: { paddingTop: 37, }, }), }, title: { color: '#FFFFFF', fontSize: 14, fontWeight: '600', }, channelName: { alignSelf: 'stretch', alignItems: 'flex-start', flex: 1, }, message: { color: '#FFFFFF', fontSize: 14, }, });