Files
mattermost-mobile/app/screens/permalink/permalink.tsx
Elias Nahum 0b4980cf65 [Gekidou] multiple fixes (#6335)
* Fix navigation stack tracking

* Fix hardwareBackPress handlers

* Use user locale for formattedTime

* Show in-app notifications when in a thread but hide when in the same thread

* Fix post draft archived & read only safe area

* Do not show reply post option in thread screen

* Open permalink as full screen modal

* Fix crash when using chinese locale

* Fix team list and call handle team change
2022-06-03 07:18:29 -04:00

241 lines
7.3 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {BackHandler, Text, TouchableOpacity, View} from 'react-native';
import Animated from 'react-native-reanimated';
import {Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
import {switchToChannelById} from '@actions/remote/channel';
import {fetchPostsAround} from '@actions/remote/post';
import CompassIcon from '@components/compass_icon';
import FormattedText from '@components/formatted_text';
import Loading from '@components/loading';
import PostList from '@components/post_list';
import {Screens} from '@constants';
import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme';
import {dismissModal} from '@screens/navigation';
import EphemeralStore from '@store/ephemeral_store';
import {closePermalink} from '@utils/permalink';
import {preventDoubleTap} from '@utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import type ChannelModel from '@typings/database/models/servers/channel';
import type PostModel from '@typings/database/models/servers/post';
type Props = {
postId: PostModel['id'];
channel?: ChannelModel;
}
const edges: Edge[] = ['left', 'right', 'top'];
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
container: {
flex: 1,
marginTop: 20,
},
wrapper: {
backgroundColor: theme.centerChannelBg,
borderRadius: 6,
flex: 1,
margin: 10,
opacity: 1,
},
header: {
alignItems: 'center',
borderTopLeftRadius: 6,
borderTopRightRadius: 6,
flexDirection: 'row',
height: 44,
paddingRight: 16,
width: '100%',
},
dividerContainer: {
backgroundColor: theme.centerChannelBg,
},
divider: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.2),
height: 1,
},
close: {
justifyContent: 'center',
height: 44,
width: 40,
paddingLeft: 7,
},
titleContainer: {
alignItems: 'center',
flex: 1,
paddingRight: 40,
},
title: {
color: theme.centerChannelColor,
fontSize: 17,
fontWeight: '600',
},
postList: {
flex: 1,
},
loading: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
bottom: {
borderBottomLeftRadius: 6,
borderBottomRightRadius: 6,
},
footer: {
alignItems: 'center',
justifyContent: 'center',
backgroundColor: theme.buttonBg,
flexDirection: 'row',
height: 43,
paddingRight: 16,
width: '100%',
},
jump: {
color: theme.buttonColor,
fontSize: 15,
fontWeight: '600',
textAlignVertical: 'center',
},
errorContainer: {
alignItems: 'center',
justifyContent: 'center',
padding: 15,
},
errorText: {
color: changeOpacity(theme.centerChannelColor, 0.4),
fontSize: 15,
},
archiveIcon: {
color: theme.centerChannelColor,
fontSize: 16,
paddingRight: 20,
},
}));
function Permalink({channel, postId}: Props) {
const [posts, setPosts] = useState<PostModel[]>([]);
const [loading, setLoading] = useState(true);
const theme = useTheme();
const serverUrl = useServerUrl();
const insets = useSafeAreaInsets();
const style = getStyleSheet(theme);
const containerStyle = useMemo(() =>
[style.container, {marginBottom: insets.bottom}],
[style, insets.bottom]);
useEffect(() => {
(async () => {
if (channel?.id) {
const data = await fetchPostsAround(serverUrl, channel.id, postId, 5);
if (data?.posts) {
setLoading(false);
setPosts(data.posts);
}
}
})();
}, [channel?.id]);
const handleClose = useCallback(() => {
dismissModal({componentId: Screens.PERMALINK});
closePermalink();
}, []);
useEffect(() => {
const listener = BackHandler.addEventListener('hardwareBackPress', () => {
if (EphemeralStore.getNavigationTopComponentId() === Screens.PERMALINK) {
handleClose();
return true;
}
return false;
});
return () => {
listener.remove();
};
}, []);
const handlePress = useCallback(preventDoubleTap(() => {
if (channel) {
switchToChannelById(serverUrl, channel?.id, channel?.teamId);
}
}), []);
return (
<SafeAreaView
style={containerStyle}
testID='permalink.screen'
edges={edges}
>
<Animated.View style={style.wrapper}>
<View style={style.header}>
<TouchableOpacity
style={style.close}
onPress={handleClose}
>
<CompassIcon
name='close'
size={20}
color={theme.centerChannelColor}
/>
</TouchableOpacity>
<View style={style.titleContainer}>
<Text
ellipsizeMode='tail'
numberOfLines={1}
style={style.title}
>
{channel?.displayName}
</Text>
</View>
</View>
<View style={style.dividerContainer}>
<View style={style.divider}/>
</View>
{loading ? (
<View style={style.loading}>
<Loading
color={theme.buttonBg}
/>
</View>
) : (
<View style={style.postList}>
<PostList
highlightedId={postId}
posts={posts}
location={Screens.PERMALINK}
lastViewedAt={0}
shouldShowJoinLeaveMessages={false}
channelId={channel!.id}
testID='permalink.post_list'
nativeID={Screens.PERMALINK}
highlightPinnedOrSaved={false}
/>
</View>
)}
<TouchableOpacity
style={[style.footer, style.bottom]}
onPress={handlePress}
testID='permalink.jump_to_recent_messages.button'
>
<FormattedText
testID='permalink.search.jump'
id='mobile.search.jump'
defaultMessage='Jump to recent messages'
style={style.jump}
/>
</TouchableOpacity>
</Animated.View>
</SafeAreaView>
);
}
export default Permalink;