diff --git a/app/hooks/navigation_button_pressed.tsx b/app/hooks/navigation_button_pressed.tsx index d586cdf85..e85ebd219 100644 --- a/app/hooks/navigation_button_pressed.tsx +++ b/app/hooks/navigation_button_pressed.tsx @@ -4,7 +4,7 @@ import {DependencyList, EffectCallback, useEffect} from 'react'; import {Navigation} from 'react-native-navigation'; -const useNavButtonPressed = (navButtonId: string, componentId: string, callback: EffectCallback, deps?: DependencyList) => { +const useNavButtonPressed = (navButtonId: string, componentId: string, callback: EffectCallback | any, deps?: DependencyList) => { useEffect(() => { const unsubscribe = Navigation.events().registerComponentListener({ navigationButtonPressed: ({buttonId}: { buttonId: string }) => { diff --git a/app/screens/apps_form/apps_form_component.tsx b/app/screens/apps_form/apps_form_component.tsx index b1ff0322a..e71a1ce3d 100644 --- a/app/screens/apps_form/apps_form_component.tsx +++ b/app/screens/apps_form/apps_form_component.tsx @@ -5,7 +5,7 @@ import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} fr import {useIntl} from 'react-intl'; import {Keyboard, ScrollView, Text, View} from 'react-native'; import Button from 'react-native-button'; -import {ImageResource, Navigation} from 'react-native-navigation'; +import {ImageResource} from 'react-native-navigation'; import {SafeAreaView} from 'react-native-safe-area-context'; import {handleGotoLocation} from '@actions/remote/command'; @@ -15,6 +15,7 @@ import {AppCallResponseTypes} from '@constants/apps'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import useDidUpdate from '@hooks/did_update'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {filterEmptyOptions} from '@utils/apps'; import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles'; import {checkDialogElementForError, checkIfErrorsMatchElements} from '@utils/integrations'; @@ -125,27 +126,15 @@ function AppsFormComponent({ const theme = useTheme(); const style = getStyleFromTheme(theme); - useEffect(() => { - const unsubscribe = Navigation.events().registerComponentListener({ - navigationButtonPressed: ({buttonId}: { buttonId: string }) => { - switch (buttonId) { - case CLOSE_BUTTON_ID: - close(); - break; - case SUBMIT_BUTTON_ID: { - if (!submitting) { - handleSubmit(); - } - break; - } - } - }, - }, componentId); - return () => { - unsubscribe.remove(); - }; + const onHandleSubmit = useCallback(() => { + if (!submitting) { + handleSubmit(); + } }, [serverUrl, componentId, submitting]); + useNavButtonPressed(CLOSE_BUTTON_ID, componentId, close, [close]); + useNavButtonPressed(SUBMIT_BUTTON_ID, componentId, onHandleSubmit, [onHandleSubmit]); + useDidUpdate(() => { dispatchValues({elements: form.fields}); }, [form]); diff --git a/app/screens/bottom_sheet/index.tsx b/app/screens/bottom_sheet/index.tsx index 20fd0f74b..bfe6f0918 100644 --- a/app/screens/bottom_sheet/index.tsx +++ b/app/screens/bottom_sheet/index.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React, {ReactNode, useCallback, useEffect, useRef} from 'react'; -import {BackHandler, DeviceEventEmitter, Keyboard, StyleSheet, useWindowDimensions, View} from 'react-native'; +import {DeviceEventEmitter, Keyboard, StyleSheet, useWindowDimensions, View} from 'react-native'; import {State, TapGestureHandler} from 'react-native-gesture-handler'; import {Navigation as RNN} from 'react-native-navigation'; import Animated, {Easing, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; @@ -10,9 +10,9 @@ import RNBottomSheet from 'reanimated-bottom-sheet'; import {Events} from '@constants'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {useIsTablet} from '@hooks/device'; import {dismissModal} from '@screens/navigation'; -import NavigationStore from '@store/navigation_store'; import {hapticFeedback} from '@utils/general'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; @@ -54,21 +54,15 @@ const BottomSheet = ({closeButtonId, componentId, initialSnapIndex = 0, renderCo return () => listener.remove(); }, [close]); - useEffect(() => { - const listener = BackHandler.addEventListener('hardwareBackPress', () => { - if (NavigationStore.getNavigationTopComponentId() === componentId) { - if (sheetRef.current) { - sheetRef.current.snapTo(1); - } else { - close(); - } - return true; - } - return false; - }); + const handleClose = useCallback(() => { + if (sheetRef.current) { + sheetRef.current.snapTo(1); + } else { + close(); + } + }, []); - return () => listener.remove(); - }, [close]); + useAndroidHardwareBackHandler(componentId, handleClose); useEffect(() => { hapticFeedback(); diff --git a/app/screens/browse_channels/browse_channels.tsx b/app/screens/browse_channels/browse_channels.tsx index 1a20ce06d..0ba53dfa7 100644 --- a/app/screens/browse_channels/browse_channels.tsx +++ b/app/screens/browse_channels/browse_channels.tsx @@ -4,7 +4,7 @@ import React, {useCallback, useEffect, useState} from 'react'; import {IntlShape, useIntl} from 'react-intl'; import {Keyboard, Platform, StyleSheet, View} from 'react-native'; -import {ImageResource, Navigation, OptionsTopBarButton} from 'react-native-navigation'; +import {ImageResource, OptionsTopBarButton} from 'react-native-navigation'; import {SafeAreaView} from 'react-native-safe-area-context'; import {joinChannel, switchToChannelById} from '@actions/remote/channel'; @@ -13,6 +13,7 @@ import Search from '@components/search'; import {Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {dismissModal, goToScreen, setButtons} from '@screens/navigation'; import {alertErrorWithFallback} from '@utils/draft'; import {changeOpacity, getKeyboardAppearanceFromTheme} from '@utils/theme'; @@ -162,27 +163,15 @@ export default function BrowseChannels(props: Props) { searchChannels(term); }, [term, searchChannels]); - useEffect(() => { - const unsubscribe = Navigation.events().registerComponentListener({ - navigationButtonPressed: ({buttonId}: { buttonId: string }) => { - switch (buttonId) { - case CLOSE_BUTTON_ID: - close(); - break; - case CREATE_BUTTON_ID: { - const screen = Screens.CREATE_OR_EDIT_CHANNEL; - const title = intl.formatMessage({id: 'mobile.create_channel.title', defaultMessage: 'New channel'}); - goToScreen(screen, title); - break; - } - } - }, - }, componentId); - return () => { - unsubscribe.remove(); - }; + const handleCreate = useCallback(() => { + const screen = Screens.CREATE_OR_EDIT_CHANNEL; + const title = intl.formatMessage({id: 'mobile.create_channel.title', defaultMessage: 'New channel'}); + goToScreen(screen, title); }, [intl.locale]); + useNavButtonPressed(CLOSE_BUTTON_ID, componentId, close, [close]); + useNavButtonPressed(CREATE_BUTTON_ID, componentId, handleCreate, [handleCreate]); + useEffect(() => { // Update header buttons in case anything related to the header changes setHeaderButtons(!adding); diff --git a/app/screens/channel_info/channel_info.tsx b/app/screens/channel_info/channel_info.tsx index 91bc7a4b3..4a4806e09 100644 --- a/app/screens/channel_info/channel_info.tsx +++ b/app/screens/channel_info/channel_info.tsx @@ -1,13 +1,13 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useEffect} from 'react'; +import React from 'react'; import {ScrollView, View} from 'react-native'; -import {Navigation} from 'react-native-navigation'; import {Edge, SafeAreaView} from 'react-native-safe-area-context'; import ChannelActions from '@components/channel_actions'; import {useTheme} from '@context/theme'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {dismissModal} from '@screens/navigation'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; @@ -44,19 +44,11 @@ const ChannelInfo = ({channelId, closeButtonId, componentId, type}: Props) => { const theme = useTheme(); const styles = getStyleSheet(theme); - useEffect(() => { - const update = Navigation.events().registerComponentListener({ - navigationButtonPressed: ({buttonId}: {buttonId: string}) => { - if (buttonId === closeButtonId) { - dismissModal({componentId}); - } - }, - }, componentId); + const onPressed = () => { + dismissModal({componentId}); + }; - return () => { - update.remove(); - }; - }, []); + useNavButtonPressed(closeButtonId, componentId, onPressed, []); return ( { - const unsubscribe = Navigation.events().registerComponentListener({navigationButtonPressed: ({buttonId}) => { - if (buttonId === START_BUTTON) { - startConversation(); - } else if (buttonId === CLOSE_BUTTON) { - close(); - } - }}, componentId); - return () => { - unsubscribe.remove(); - }; - }, [startConversation]); + useNavButtonPressed(START_BUTTON, componentId, startConversation, [startConversation]); + useNavButtonPressed(CLOSE_BUTTON, componentId, close, [close]); useEffect(() => { mounted.current = true; diff --git a/app/screens/create_or_edit_channel/create_or_edit_channel.tsx b/app/screens/create_or_edit_channel/create_or_edit_channel.tsx index 12a125bf0..f3d7dd5aa 100644 --- a/app/screens/create_or_edit_channel/create_or_edit_channel.tsx +++ b/app/screens/create_or_edit_channel/create_or_edit_channel.tsx @@ -1,17 +1,18 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useEffect, useReducer, useCallback, useMemo} from 'react'; +import React, {useCallback, useEffect, useMemo, useReducer, useState} from 'react'; import {useIntl} from 'react-intl'; import {Keyboard} from 'react-native'; -import {ImageResource, Navigation} from 'react-native-navigation'; +import {ImageResource} from 'react-native-navigation'; -import {patchChannel as handlePatchChannel, createChannel, switchToChannelById} from '@actions/remote/channel'; +import {createChannel, patchChannel as handlePatchChannel, switchToChannelById} from '@actions/remote/channel'; import CompassIcon from '@components/compass_icon'; import {General} from '@constants'; import {MIN_CHANNEL_NAME_LENGTH} from '@constants/channel'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {buildNavigationButton, dismissModal, popTopScreen, setButtons} from '@screens/navigation'; import {validateDisplayName} from '@utils/channel'; @@ -220,27 +221,13 @@ const CreateOrEditChannel = ({ close(componentId, isModal); }, [channel?.id, channel?.type, displayName, header, isModal, purpose, isValidDisplayName]); - useEffect(() => { - const update = Navigation.events().registerComponentListener({ - navigationButtonPressed: ({buttonId}: {buttonId: string}) => { - switch (buttonId) { - case CLOSE_BUTTON_ID: - close(componentId, isModal); - break; - case CREATE_BUTTON_ID: - onCreateChannel(); - break; - case EDIT_BUTTON_ID: - onUpdateChannel(); - break; - } - }, - }, componentId); + const handleClose = useCallback(() => { + close(componentId, isModal); + }, [isModal]); - return () => { - update.remove(); - }; - }, [onCreateChannel, onUpdateChannel, isModal]); + useNavButtonPressed(CLOSE_BUTTON_ID, componentId, handleClose, [handleClose]); + useNavButtonPressed(CREATE_BUTTON_ID, componentId, onCreateChannel, [onCreateChannel]); + useNavButtonPressed(EDIT_BUTTON_ID, componentId, onUpdateChannel, [onUpdateChannel]); return ( { - const unsubscribe = Navigation.events().registerComponentListener({ - navigationButtonPressed: ({buttonId}: { buttonId: string }) => { - switch (buttonId) { - case closeButtonId: { - onClose(); - break; - } - case RIGHT_BUTTON.id: - onSavePostMessage(); - break; - } - }, - }, componentId); - - return () => { - unsubscribe.remove(); - }; - }, [postMessage]); - useDidUpdate(() => { // Workaround to avoid iOS emdash autocorrect in Code Blocks if (Platform.OS === 'ios') { @@ -254,6 +234,9 @@ const EditPost = ({componentId, maxPostSize, post, closeButtonId, hasFilesAttach }; }); + useNavButtonPressed(RIGHT_BUTTON.id, componentId, onSavePostMessage, [postMessage]); + useNavButtonPressed(closeButtonId, componentId, onClose, []); + if (isUpdating) { return ( diff --git a/app/screens/edit_profile/edit_profile.tsx b/app/screens/edit_profile/edit_profile.tsx index 1e1118688..781297a46 100644 --- a/app/screens/edit_profile/edit_profile.tsx +++ b/app/screens/edit_profile/edit_profile.tsx @@ -3,9 +3,8 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {useIntl} from 'react-intl'; -import {BackHandler, DeviceEventEmitter, Keyboard, Platform, StyleSheet, View} from 'react-native'; +import {DeviceEventEmitter, Keyboard, Platform, StyleSheet, View} from 'react-native'; import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; -import {Navigation} from 'react-native-navigation'; import {Edge, SafeAreaView} from 'react-native-safe-area-context'; import {updateLocalUser} from '@actions/local/user'; @@ -15,8 +14,9 @@ import TabletTitle from '@components/tablet_title'; import {Events} from '@constants'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {dismissModal, popTopScreen, setButtons} from '@screens/navigation'; -import NavigationStore from '@store/navigation_store'; import {preventDoubleTap} from '@utils/tap'; import ProfileForm from './components/form'; @@ -85,39 +85,6 @@ const EditProfile = ({ }; }, [isTablet, theme.centerChannelColor]); - useEffect(() => { - const unsubscribe = Navigation.events().registerComponentListener({ - navigationButtonPressed: ({buttonId}: { buttonId: string }) => { - switch (buttonId) { - case UPDATE_BUTTON_ID: - submitUser(); - break; - case CLOSE_BUTTON_ID: - close(); - break; - } - }, - }, componentId); - - return () => { - unsubscribe.remove(); - }; - }, [userInfo]); - - useEffect(() => { - const backHandler = BackHandler.addEventListener('hardwareBackPress', () => { - if (NavigationStore.getNavigationTopComponentId() === componentId) { - close(); - return true; - } - - return false; - }); - return () => { - backHandler.remove(); - }; - }, []); - useEffect(() => { if (!isTablet) { setButtons(componentId, { @@ -136,7 +103,6 @@ const EditProfile = ({ popTopScreen(componentId); } }, []); - const enableSaveButton = useCallback((value: boolean) => { if (!isTablet) { const buttons = { @@ -149,24 +115,6 @@ const EditProfile = ({ } setCanSave(value); }, [componentId, rightButton]); - - const onUpdateProfilePicture = useCallback((newProfileImage: NewProfileImage) => { - changedProfilePicture.current = newProfileImage; - enableSaveButton(true); - }, [enableSaveButton]); - - const onUpdateField = useCallback((fieldKey: string, name: string) => { - const update = {...userInfo}; - update[fieldKey] = name; - setUserInfo(update); - - // @ts-expect-error access object property by string key - const currentValue = currentUser[fieldKey]; - const didChange = currentValue !== name; - hasUpdateUserInfo.current = currentValue !== name; - enableSaveButton(didChange); - }, [userInfo, currentUser, enableSaveButton]); - const submitUser = useCallback(preventDoubleTap(async () => { enableSaveButton(false); setError(undefined); @@ -209,6 +157,27 @@ const EditProfile = ({ } }), [userInfo, enableSaveButton]); + useAndroidHardwareBackHandler(componentId, close); + useNavButtonPressed(UPDATE_BUTTON_ID, componentId, submitUser, [userInfo]); + useNavButtonPressed(CLOSE_BUTTON_ID, componentId, close, []); + + const onUpdateProfilePicture = useCallback((newProfileImage: NewProfileImage) => { + changedProfilePicture.current = newProfileImage; + enableSaveButton(true); + }, [enableSaveButton]); + + const onUpdateField = useCallback((fieldKey: string, name: string) => { + const update = {...userInfo}; + update[fieldKey] = name; + setUserInfo(update); + + // @ts-expect-error access object property by string key + const currentValue = currentUser[fieldKey]; + const didChange = currentValue !== name; + hasUpdateUserInfo.current = currentValue !== name; + enableSaveButton(didChange); + }, [userInfo, currentUser, enableSaveButton]); + const resetScreen = useCallback((resetError: Error) => { setError(resetError?.message); Keyboard.dismiss(); diff --git a/app/screens/emoji_picker/index.tsx b/app/screens/emoji_picker/index.tsx index cb66e904d..612ddd8a7 100644 --- a/app/screens/emoji_picker/index.tsx +++ b/app/screens/emoji_picker/index.tsx @@ -3,9 +3,9 @@ import React, {useCallback, useEffect} from 'react'; import {Keyboard} from 'react-native'; -import {Navigation} from 'react-native-navigation'; import EmojiPicker from '@components/emoji_picker'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {dismissModal, setButtons} from '@screens/navigation'; type Props = { @@ -14,36 +14,28 @@ type Props = { closeButton: never; }; +const EMOJI_PICKER_BUTTON = 'close-add-reaction'; + const EmojiPickerScreen = ({closeButton, componentId, onEmojiPress}: Props) => { useEffect(() => { setButtons(componentId, { leftButtons: [ { icon: closeButton, - id: 'close-add-reaction', + id: EMOJI_PICKER_BUTTON, testID: 'close.emoji_picker.button', }, ], rightButtons: [], }); - - const unsubscribe = Navigation.events().registerComponentListener({ - navigationButtonPressed: ({buttonId}: { buttonId: string }) => { - if (buttonId === 'close-add-reaction') { - close(); - } - }, - }, componentId); - - return () => { - unsubscribe.remove(); - }; }, []); - const close = useCallback(() => { + const close = () => { Keyboard.dismiss(); - dismissModal(); - }, []); + dismissModal({componentId}); + }; + + useNavButtonPressed(EMOJI_PICKER_BUTTON, componentId, close, []); const handleEmojiPress = useCallback((emoji: string) => { onEmojiPress(emoji); diff --git a/app/screens/permalink/permalink.tsx b/app/screens/permalink/permalink.tsx index 9275bbbdf..685bd25e5 100644 --- a/app/screens/permalink/permalink.tsx +++ b/app/screens/permalink/permalink.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React, {useCallback, useEffect, useMemo, useState} from 'react'; -import {Alert, BackHandler, Text, TouchableOpacity, View} from 'react-native'; +import {Alert, Text, TouchableOpacity, View} from 'react-native'; import Animated from 'react-native-reanimated'; import {Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context'; @@ -17,10 +17,10 @@ import {Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import DatabaseManager from '@database/manager'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {useIsTablet} from '@hooks/device'; import {getChannelById, getMyChannel} from '@queries/servers/channel'; import {dismissModal} from '@screens/navigation'; -import NavigationStore from '@store/navigation_store'; import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles'; import {closePermalink} from '@utils/permalink'; import {preventDoubleTap} from '@utils/tap'; @@ -251,20 +251,7 @@ function Permalink({ closePermalink(); }, [error]); - useEffect(() => { - const listener = BackHandler.addEventListener('hardwareBackPress', () => { - if (NavigationStore.getNavigationTopComponentId() === Screens.PERMALINK) { - handleClose(); - return true; - } - - return false; - }); - - return () => { - listener.remove(); - }; - }, []); + useAndroidHardwareBackHandler(Screens.PERMALINK, handleClose); const handlePress = useCallback(preventDoubleTap(() => { if (channel) { diff --git a/app/screens/pinned_messages/pinned_messages.tsx b/app/screens/pinned_messages/pinned_messages.tsx index b42159769..eed9b5b14 100644 --- a/app/screens/pinned_messages/pinned_messages.tsx +++ b/app/screens/pinned_messages/pinned_messages.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React, {useCallback, useEffect, useMemo, useState} from 'react'; -import {BackHandler, DeviceEventEmitter, FlatList, StyleSheet, View} from 'react-native'; +import {DeviceEventEmitter, FlatList, StyleSheet, View} from 'react-native'; import {Edge, SafeAreaView} from 'react-native-safe-area-context'; import {fetchPinnedPosts} from '@actions/remote/post'; @@ -12,9 +12,9 @@ import Post from '@components/post_list/post'; import {Events, Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {popTopScreen} from '@screens/navigation'; -import NavigationStore from '@store/navigation_store'; -import {isDateLine, getDateForDateLine, selectOrderedPosts} from '@utils/post_list'; +import {getDateForDateLine, isDateLine, selectOrderedPosts} from '@utils/post_list'; import EmptyState from './empty'; @@ -23,7 +23,7 @@ import type PostModel from '@typings/database/models/servers/post'; type Props = { channelId: string; - componentId?: string; + componentId: string; currentTimezone: string | null; isCRTEnabled: boolean; isTimezoneEnabled: boolean; @@ -78,18 +78,7 @@ function SavedMessages({ }); }, []); - useEffect(() => { - const listener = BackHandler.addEventListener('hardwareBackPress', () => { - if (NavigationStore.getNavigationTopComponentId() === componentId) { - close(); - return true; - } - - return false; - }); - - return () => listener.remove(); - }, [componentId]); + useAndroidHardwareBackHandler(componentId, close); const onViewableItemsChanged = useCallback(({viewableItems}: ViewableItemsChanged) => { if (!viewableItems.length) { diff --git a/app/screens/post_options/post_options.tsx b/app/screens/post_options/post_options.tsx index 7a4a84a9d..20fb1c036 100644 --- a/app/screens/post_options/post_options.tsx +++ b/app/screens/post_options/post_options.tsx @@ -2,12 +2,12 @@ // See LICENSE.txt for license information. import {useManagedConfig} from '@mattermost/react-native-emm'; -import React, {useEffect} from 'react'; -import {Navigation} from 'react-native-navigation'; +import React from 'react'; import {CopyPermalinkOption, FollowThreadOption, ReplyOption, SaveOption} from '@components/common_post_options'; import {ITEM_HEIGHT} from '@components/menu_item'; import {Screens} from '@constants'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import BottomSheet from '@screens/bottom_sheet'; import {dismissModal} from '@screens/navigation'; import {isSystemMessage} from '@utils/post'; @@ -22,6 +22,8 @@ import ReactionBar from './reaction_bar'; import type PostModel from '@typings/database/models/servers/post'; import type ThreadModel from '@typings/database/models/servers/thread'; +const POST_OPTIONS_BUTTON = 'close-post-options'; + type PostOptionsProps = { canAddReaction: boolean; canDelete: boolean; @@ -36,7 +38,6 @@ type PostOptionsProps = { thread?: ThreadModel; componentId: string; }; - const PostOptions = ({ canAddReaction, canDelete, canEdit, canMarkAsUnread, canPin, canReply, @@ -45,22 +46,11 @@ const PostOptions = ({ }: PostOptionsProps) => { const managedConfig = useManagedConfig(); - useEffect(() => { - const unsubscribe = Navigation.events().registerComponentListener({ - navigationButtonPressed: ({buttonId}: { buttonId: string }) => { - switch (buttonId) { - case 'close-post-options': { - dismissModal({componentId}); - break; - } - } - }, - }, componentId); + const close = () => { + dismissModal({componentId}); + }; - return () => { - unsubscribe.remove(); - }; - }, []); + useNavButtonPressed(POST_OPTIONS_BUTTON, componentId, close, []); const isSystemPost = isSystemMessage(post); @@ -134,7 +124,7 @@ const PostOptions = ({ return ( { }; }, [theme.centerChannelColor]); - const close = useCallback(() => { + const close = () => { dismissModal({componentId}); - }, []); + }; useEffect(() => { setButtons(componentId, { @@ -93,33 +93,9 @@ const Settings = ({componentId, showHelp, siteName}: SettingsProps) => { }); }, []); - useEffect(() => { - const backHandler = BackHandler.addEventListener('hardwareBackPress', () => { - if (NavigationStore.getNavigationTopComponentId() === componentId) { - close(); - return true; - } + useAndroidHardwareBackHandler(componentId, close); - return false; - }); - return () => { - backHandler.remove(); - }; - }, []); - - useEffect(() => { - const unsubscribe = Navigation.events().registerComponentListener({ - navigationButtonPressed: ({buttonId}: { buttonId: string }) => { - if (buttonId === CLOSE_BUTTON_ID) { - close(); - } - }, - }, componentId); - - return () => { - unsubscribe.remove(); - }; - }, []); + useNavButtonPressed(CLOSE_BUTTON_ID, componentId, close, []); const onPressHandler = () => { return Alert.alert( diff --git a/app/screens/thread_options/thread_options.tsx b/app/screens/thread_options/thread_options.tsx index c51d9c968..ec6d0d218 100644 --- a/app/screens/thread_options/thread_options.tsx +++ b/app/screens/thread_options/thread_options.tsx @@ -2,9 +2,8 @@ // See LICENSE.txt for license information. import {useManagedConfig} from '@mattermost/react-native-emm'; -import React, {useEffect} from 'react'; +import React from 'react'; import {View} from 'react-native'; -import {Navigation} from 'react-native-navigation'; import {CopyPermalinkOption, FollowThreadOption, ReplyOption, SaveOption} from '@components/common_post_options'; import FormattedText from '@components/formatted_text'; @@ -12,6 +11,7 @@ import {ITEM_HEIGHT} from '@components/menu_item'; import {Screens} from '@constants'; import {useTheme} from '@context/theme'; import {useIsTablet} from '@hooks/device'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import BottomSheet from '@screens/bottom_sheet'; import {dismissModal} from '@screens/navigation'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; @@ -45,6 +45,8 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { }; }); +const THREAD_OPTIONS_BUTTON = 'close-thread-options'; + const ThreadOptions = ({ componentId, isSaved, @@ -57,19 +59,11 @@ const ThreadOptions = ({ const style = getStyleSheet(theme); - useEffect(() => { - const unsubscribe = Navigation.events().registerComponentListener({ - navigationButtonPressed: ({buttonId}: { buttonId: string }) => { - if (buttonId === 'close-thread-options') { - dismissModal({componentId}); - } - }, - }, componentId); + const close = () => { + dismissModal({componentId}); + }; - return () => { - unsubscribe.remove(); - }; - }, []); + useNavButtonPressed(THREAD_OPTIONS_BUTTON, componentId, close, []); const options = [