mattermost-mobile/app/screens/notification/index.tsx
Daniel Espino García 4c8594d330
Add linter rules for import order and type member delimiters (#5514)
* Add linter rules for import order and type member delimiters

* Remove unneeded group

* Group all app/* imports before the internal imports

* Move app/ imports before parent imports

* Separate @node_modules imports into a different group

* Substitute app paths by aliases

* Fix @node_modules import order and add test related modules

* Add aliases for types and test, and group import types
2021-07-23 11:06:04 +02:00

209 lines
6.4 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useEffect, useRef, useState} from 'react';
import {Platform, StyleSheet, Text, TouchableOpacity, View} from 'react-native';
import * as Animatable from 'react-native-animatable';
import {PanGestureHandler} from 'react-native-gesture-handler';
import {Navigation} from 'react-native-navigation';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {useDispatch} from 'react-redux';
import {popToRoot, dismissAllModals, dismissOverlay} from '@actions/navigation';
import {loadFromPushNotification} from '@actions/views/root';
import {NavigationTypes} from '@constants';
import EventEmitter from '@mm-redux/utils/event_emitter';
import {changeOpacity} from '@utils/theme';
import NotificationIcon from './notification_icon';
import NotificationTitle from './notification_title';
interface NotificationProps {
componentId: string;
notification: NotificationWithData;
}
interface SlideAnimation extends Animatable.CustomAnimation {
from: {
translateY: number;
};
to: {
translateY: number;
};
}
const AUTO_DISMISS_TIME_MILLIS = 5000;
const initialAnimation: SlideAnimation = {
from: {
translateY: -100,
},
to: {
translateY: 0,
},
};
const Notification = ({componentId, notification}: NotificationProps) => {
const [animation, setAnimation] = useState<SlideAnimation>(initialAnimation);
const insets = useSafeAreaInsets();
const dispatch = useDispatch();
const dismissTimerRef = useRef<NodeJS.Timeout | null>(null);
const tapped = useRef<boolean>(false);
const animateDismissOverlay = () => {
cancelDismissTimer();
setAnimation({
from: {
translateY: 0,
},
to: {
translateY: -100,
},
});
dismissTimerRef.current = setTimeout(dismiss, 1000);
};
const cancelDismissTimer = () => {
if (dismissTimerRef.current) {
clearTimeout(dismissTimerRef.current);
}
};
const dismiss = () => {
cancelDismissTimer();
dismissOverlay(componentId);
};
const notificationTapped = () => {
tapped.current = true;
EventEmitter.emit(NavigationTypes.CLOSE_MAIN_SIDEBAR);
EventEmitter.emit(NavigationTypes.CLOSE_SETTINGS_SIDEBAR);
dismiss();
if (!notification.payload?.userInfo?.local) {
dispatch(loadFromPushNotification(notification));
}
};
useEffect(() => {
dismissTimerRef.current = setTimeout(() => {
if (!tapped.current) {
animateDismissOverlay();
}
}, AUTO_DISMISS_TIME_MILLIS);
return cancelDismissTimer;
}, []);
useEffect(() => {
const didDismissListener = Navigation.events().registerComponentDidDisappearListener(async ({componentId: screen}) => {
if (componentId === screen && tapped.current) {
await dismissAllModals();
await popToRoot();
}
});
return () => {
didDismissListener.remove();
};
}, []);
useEffect(() => {
EventEmitter.on(NavigationTypes.NAVIGATION_SHOW_OVERLAY, dismiss);
return () => EventEmitter.off(NavigationTypes.NAVIGATION_SHOW_OVERLAY, dismiss);
}, []);
const message = notification.payload?.body || notification.payload?.message;
return (
<PanGestureHandler
onGestureEvent={animateDismissOverlay}
minOffsetY={-20}
>
<Animatable.View
duration={250}
style={[styles.container, {height: (styles.container.height || 0) + (insets.top / 2), paddingTop: (insets.top / 2)}]}
useNativeDriver={true}
animation={animation}
testID='in_app_notification.screen'
>
<View style={styles.flex}>
<TouchableOpacity
style={styles.touchable}
onPress={notificationTapped}
activeOpacity={1}
>
<NotificationIcon
fromWebhook={notification.payload?.from_webhook === 'true'}
senderId={notification.payload?.sender_id || ''}
useUserIcon={notification.payload?.use_user_icon === 'true'}
overrideIconUrl={notification.payload?.override_icon_url}
/>
<View style={styles.titleContainer}>
<NotificationTitle channelName={notification.payload?.channel_name || ''}/>
<View style={styles.flex}>
<Text
numberOfLines={1}
ellipsizeMode='tail'
style={styles.message}
testID='in_app_notification.message'
>
{message}
</Text>
</View>
</View>
</TouchableOpacity>
</View>
</Animatable.View>
</PanGestureHandler>
);
};
const styles = 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,
},
}),
},
flex: {
flex: 1,
},
message: {
color: '#FFFFFF',
fontSize: 14,
},
titleContainer: {
flex: 1,
flexDirection: 'column',
alignSelf: 'stretch',
alignItems: 'flex-start',
marginLeft: 10,
...Platform.select({
android: {
marginTop: 5,
height: 50,
},
ios: {
paddingTop: 37,
},
}),
},
touchable: {
flex: 1,
flexDirection: 'row',
},
});
export default Notification;