From 8b9779d4b3ab81cc1146d189116b358b1ff1a001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20V=C3=A9lez?= Date: Thu, 5 Dec 2024 15:53:54 -0500 Subject: [PATCH] MM-56899 - prevent app block when setting custom status if no internet (#8283) * MM-56899 - prevent app block when setting custom status if no internet * remove alert and use build in error message * remove unused translations * implement pr feedback * keep function in local file * remove unnecessary change * fix placeholder position * block the done button while the server replies * add close button to the modal --- app/hooks/navigation_button_pressed.ts | 1 - .../components/custom_status_input.tsx | 11 +++- app/screens/custom_status/custom_status.tsx | 52 +++++++++++++------ .../custom_label/custom_label.tsx | 6 ++- 4 files changed, 49 insertions(+), 21 deletions(-) diff --git a/app/hooks/navigation_button_pressed.ts b/app/hooks/navigation_button_pressed.ts index 5da070b06..c8a7ac24d 100644 --- a/app/hooks/navigation_button_pressed.ts +++ b/app/hooks/navigation_button_pressed.ts @@ -22,4 +22,3 @@ const useNavButtonPressed = (navButtonId: string, componentId: string, callback: }; export default useNavButtonPressed; - diff --git a/app/screens/custom_status/components/custom_status_input.tsx b/app/screens/custom_status/components/custom_status_input.tsx index 42d82bb50..12a2b45b1 100644 --- a/app/screens/custom_status/components/custom_status_input.tsx +++ b/app/screens/custom_status/components/custom_status_input.tsx @@ -3,7 +3,7 @@ import React from 'react'; import {useIntl} from 'react-intl'; -import {TextInput, View} from 'react-native'; +import {Platform, TextInput, View} from 'react-native'; import ClearButton from '@components/custom_status/clear_button'; import {CUSTOM_STATUS_TEXT_CHARACTER_LIMIT} from '@constants/custom_status'; @@ -35,7 +35,14 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { color: theme.centerChannelColor, flex: 1, paddingHorizontal: 16, - textAlignVertical: 'center', + ...Platform.select({ + ios: { + paddingVertical: 25, + }, + android: { + textAlignVertical: 'center', + }, + }), height: '100%', ...typography('Body', 200, 'Regular'), }, diff --git a/app/screens/custom_status/custom_status.tsx b/app/screens/custom_status/custom_status.tsx index 8a64aa823..aa6f5b4b6 100644 --- a/app/screens/custom_status/custom_status.tsx +++ b/app/screens/custom_status/custom_status.tsx @@ -2,13 +2,15 @@ // See LICENSE.txt for license information. import moment from 'moment-timezone'; -import React, {useCallback, useEffect, useMemo, useReducer} from 'react'; +import React, {useCallback, useEffect, useMemo, useReducer, useState} from 'react'; import {useIntl} from 'react-intl'; import {DeviceEventEmitter, Keyboard, KeyboardAvoidingView, Platform, ScrollView, View} from 'react-native'; +import {type Options} from 'react-native-navigation'; import {type Edge, SafeAreaView} from 'react-native-safe-area-context'; import {updateLocalCustomStatus} from '@actions/local/user'; import {removeRecentCustomStatus, updateCustomStatus, unsetCustomStatus} from '@actions/remote/user'; +import CompassIcon from '@components/compass_icon'; import TabletTitle from '@components/tablet_title'; import {Events, Screens} from '@constants'; import {CustomStatusDurationEnum, SET_CUSTOM_STATUS_FAILURE} from '@constants/custom_status'; @@ -145,6 +147,17 @@ function reducer(state: NewStatusType, action: { } } +const dismissModalAndKeyboard = (isTablet: boolean, options?: Options & { componentId: AvailableScreens}) => { + if (isTablet) { + DeviceEventEmitter.emit(Events.ACCOUNT_SELECT_TABLET_VIEW, ''); + } else { + dismissModal(options); + } + Keyboard.dismiss(); +}; + +const closeCustomStatusModalId = 'close-custom-status'; + const CustomStatus = ({ customStatusExpirySupported, currentUser, @@ -156,7 +169,10 @@ const CustomStatus = ({ const theme = useTheme(); const style = getStyleSheet(theme); const serverUrl = useServerUrl(); - + const [isBtnEnabled, setIsBtnEnabled] = useState(true); + useNavButtonPressed('close-custom-status', componentId, () => { + dismissModalAndKeyboard(isTablet, {componentId}); + }, [componentId, isTablet]); const storedStatus = useMemo(() => { return getUserCustomStatus(currentUser); }, [currentUser]); @@ -222,6 +238,7 @@ const CustomStatus = ({ initialDuration: newStatus.duration, intl, theme, + closeButtonId: 'close-custom-status', }; if (isTablet) { @@ -242,6 +259,7 @@ const CustomStatus = ({ if (!currentUser) { return; } + setIsBtnEnabled(false); if (isStatusSet) { let isStatusSame = @@ -264,12 +282,15 @@ const CustomStatus = ({ status.duration = newStatus.duration; status.expires_at = newExpiresAt; } + const {error} = await updateCustomStatus(serverUrl, status); if (error) { + dismissModalAndKeyboard(isTablet, {componentId}); DeviceEventEmitter.emit(SET_CUSTOM_STATUS_FAILURE); + setIsBtnEnabled(true); return; } - + setIsBtnEnabled(true); updateLocalCustomStatus(serverUrl, currentUser, status); dispatchStatus({type: 'fromUserCustomStatus', status}); } @@ -280,13 +301,8 @@ const CustomStatus = ({ updateLocalCustomStatus(serverUrl, currentUser, undefined); } } - Keyboard.dismiss(); - if (isTablet) { - DeviceEventEmitter.emit(Events.ACCOUNT_SELECT_TABLET_VIEW, ''); - } else { - dismissModal(); - } - }, [newStatus, isStatusSet, storedStatus, currentUser]); + dismissModalAndKeyboard(isTablet, {componentId}); + }, [newStatus, isStatusSet, storedStatus, currentUser, isTablet]); const openEmojiPicker = useCallback(preventDoubleTap(() => { openAsBottomSheet({ @@ -299,22 +315,19 @@ const CustomStatus = ({ }), [theme, intl, handleEmojiClick]); const handleBackButton = useCallback(() => { - if (isTablet) { - DeviceEventEmitter.emit(Events.ACCOUNT_SELECT_TABLET_VIEW, ''); - } else { - dismissModal({componentId}); - } + dismissModalAndKeyboard(isTablet, {componentId}); }, [componentId, isTablet]); useAndroidHardwareBackHandler(componentId, handleBackButton); useNavButtonPressed(BTN_UPDATE_STATUS, componentId, handleSetStatus, [handleSetStatus]); useEffect(() => { + const closeButton = CompassIcon.getImageSourceSync('close', 24, theme.sidebarHeaderTextColor); mergeNavigationOptions(componentId, { topBar: { rightButtons: [ { - enabled: true, + enabled: isBtnEnabled, id: BTN_UPDATE_STATUS, showAsAction: 'always', testID: 'custom_status.done.button', @@ -322,9 +335,14 @@ const CustomStatus = ({ color: theme.sidebarHeaderTextColor, }, ], + leftButtons: [{ + id: closeCustomStatusModalId, + icon: closeButton, + testID: 'close.custom_status.button', + }], }, }); - }, []); + }, [isBtnEnabled]); return ( <> diff --git a/app/screens/home/account/components/options/custom_status/custom_label/custom_label.tsx b/app/screens/home/account/components/options/custom_status/custom_label/custom_label.tsx index e1b89995d..969399e81 100644 --- a/app/screens/home/account/components/options/custom_status/custom_label/custom_label.tsx +++ b/app/screens/home/account/components/options/custom_status/custom_label/custom_label.tsx @@ -10,6 +10,7 @@ import CustomStatusExpiry from '@components/custom_status/custom_status_expiry'; import FormattedText from '@components/formatted_text'; import {useTheme} from '@context/theme'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; import CustomStatusText from './custom_status_text'; @@ -38,8 +39,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { color: changeOpacity(theme.centerChannelColor, 0.35), }, retryMessage: { + position: 'absolute', + top: 25, + left: 40, color: theme.errorTextColor, - paddingBottom: 25, + ...typography('Body', 100), }, }; });