diff --git a/native/chat/settings/delete-thread.react.js b/native/chat/settings/delete-thread.react.js index 6be2a0b3f..6b79bdecf 100644 --- a/native/chat/settings/delete-thread.react.js +++ b/native/chat/settings/delete-thread.react.js @@ -1,333 +1,274 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import { Text, View, TextInput as BaseTextInput, ScrollView, Alert, ActivityIndicator, } from 'react-native'; import { deleteThreadActionTypes, deleteThread, } from 'lib/actions/thread-actions'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors'; import { threadInfoSelector } from 'lib/selectors/thread-selectors'; import { identifyInvalidatedThreads } from 'lib/shared/thread-utils'; import type { LoadingStatus } from 'lib/types/loading-types'; import type { ThreadInfo, LeaveThreadPayload } from 'lib/types/thread-types'; import { useServerCall, useDispatchActionPromise, type DispatchActionPromise, } from 'lib/utils/action-utils'; import Button from '../../components/button.react'; -import TextInput from '../../components/text-input.react'; import { clearThreadsActionType } from '../../navigation/action-types'; import { NavContext, type NavAction, } from '../../navigation/navigation-context'; import type { NavigationRoute } from '../../navigation/route-names'; import { useSelector } from '../../redux/redux-utils'; import { type Colors, useColors, useStyles } from '../../themes/colors'; import type { GlobalTheme } from '../../types/themes'; import type { ChatNavigationProp } from '../chat.react'; export type DeleteThreadParams = { +threadInfo: ThreadInfo, }; type BaseProps = { +navigation: ChatNavigationProp<'DeleteThread'>, +route: NavigationRoute<'DeleteThread'>, }; type Props = { ...BaseProps, // Redux state +threadInfo: ?ThreadInfo, +loadingStatus: LoadingStatus, +activeTheme: ?GlobalTheme, +colors: Colors, +styles: typeof unboundStyles, // Redux dispatch functions +dispatchActionPromise: DispatchActionPromise, // async functions that hit server APIs - +deleteThread: ( - threadID: string, - currentAccountPassword: string, - ) => Promise, + +deleteThread: (threadID: string) => Promise, // withNavContext +navDispatch: (action: NavAction) => void, }; -type State = { - +password: string, -}; -class DeleteThread extends React.PureComponent { - state: State = { - password: '', - }; +class DeleteThread extends React.PureComponent { mounted = false; passwordInput: ?React.ElementRef; static getThreadInfo(props: Props): ThreadInfo { const { threadInfo } = props; if (threadInfo) { return threadInfo; } return props.route.params.threadInfo; } componentDidMount() { this.mounted = true; } componentWillUnmount() { this.mounted = false; } guardedSetState(change, callback) { if (this.mounted) { this.setState(change, callback); } } componentDidUpdate(prevProps: Props) { const oldReduxThreadInfo = prevProps.threadInfo; const newReduxThreadInfo = this.props.threadInfo; if (newReduxThreadInfo && newReduxThreadInfo !== oldReduxThreadInfo) { this.props.navigation.setParams({ threadInfo: newReduxThreadInfo }); } } render() { const buttonContent = this.props.loadingStatus === 'loading' ? ( ) : ( Delete chat ); const threadInfo = DeleteThread.getThreadInfo(this.props); - const { panelForegroundTertiaryLabel } = this.props.colors; return ( {`The chat "${threadInfo.uiName}" will be permanently deleted. `} There is no way to reverse this. - PASSWORD - - - ); } - onChangePasswordText = (newPassword: string) => { - this.guardedSetState({ password: newPassword }); - }; - passwordInputRef = ( passwordInput: ?React.ElementRef, ) => { this.passwordInput = passwordInput; }; focusPasswordInput = () => { invariant(this.passwordInput, 'passwordInput should be set'); this.passwordInput.focus(); }; submitDeletion = () => { - if (this.state.password === '') { - return; - } - this.props.dispatchActionPromise( deleteThreadActionTypes, this.deleteThread(), ); }; async deleteThread() { const threadInfo = DeleteThread.getThreadInfo(this.props); const { navDispatch } = this.props; navDispatch({ type: clearThreadsActionType, payload: { threadIDs: [threadInfo.id] }, }); try { - const result = await this.props.deleteThread( - threadInfo.id, - this.state.password, - ); + const result = await this.props.deleteThread(threadInfo.id); const invalidated = identifyInvalidatedThreads( result.updatesResult.newUpdates, ); navDispatch({ type: clearThreadsActionType, payload: { threadIDs: [...invalidated] }, }); return result; } catch (e) { - if ( - e.message === 'invalid_credentials' || - e.message === 'invalid_parameters' - ) { + if (e.message === 'invalid_credentials') { Alert.alert( - 'Incorrect password', - 'The password you entered is incorrect', - [{ text: 'OK', onPress: this.onErrorAlertAcknowledged }], + 'Permission not granted', + 'You do not have permission to delete this thread', + [{ text: 'OK' }], { cancelable: false }, ); } else { - Alert.alert( - 'Unknown error', - 'Uhh... try again?', - [{ text: 'OK', onPress: this.onErrorAlertAcknowledged }], - { cancelable: false }, - ); + Alert.alert('Unknown error', 'Uhh... try again?', [{ text: 'OK' }], { + cancelable: false, + }); } } } - - onErrorAlertAcknowledged = () => { - this.guardedSetState({ password: '' }, this.focusPasswordInput); - }; } const unboundStyles = { - baseDeleteButton: { + deleteButton: { + backgroundColor: 'redButton', borderRadius: 5, flex: 1, marginHorizontal: 24, marginVertical: 12, padding: 12, }, - deleteButtonEnabled: { - backgroundColor: 'redButton', - }, - deleteButtonDisabled: { - backgroundColor: 'disabledButton', - }, deleteText: { color: 'white', fontSize: 18, textAlign: 'center', }, header: { color: 'panelBackgroundLabel', fontSize: 12, fontWeight: '400', paddingBottom: 3, paddingHorizontal: 24, }, input: { color: 'panelForegroundLabel', flex: 1, fontFamily: 'Arial', fontSize: 16, paddingVertical: 0, borderBottomColor: 'transparent', }, scrollView: { backgroundColor: 'panelBackground', }, scrollViewContentContainer: { paddingTop: 24, }, section: { backgroundColor: 'panelForeground', borderBottomWidth: 1, borderColor: 'panelForegroundBorder', borderTopWidth: 1, flexDirection: 'row', justifyContent: 'space-between', marginBottom: 24, paddingHorizontal: 24, paddingVertical: 12, }, warningText: { color: 'panelForegroundLabel', fontSize: 16, marginBottom: 24, marginHorizontal: 24, textAlign: 'center', }, }; const loadingStatusSelector = createLoadingStatusSelector( deleteThreadActionTypes, ); const ConnectedDeleteThread: React.ComponentType = React.memo( function ConnectedDeleteThread(props: BaseProps) { const threadID = props.route.params.threadInfo.id; const threadInfo = useSelector( state => threadInfoSelector(state)[threadID], ); const loadingStatus = useSelector(loadingStatusSelector); const activeTheme = useSelector(state => state.globalThemeInfo.activeTheme); const colors = useColors(); const styles = useStyles(unboundStyles); const dispatchActionPromise = useDispatchActionPromise(); const callDeleteThread = useServerCall(deleteThread); const navContext = React.useContext(NavContext); invariant(navContext, 'NavContext should be set in DeleteThread'); const navDispatch = navContext.dispatch; return ( ); }, ); export default ConnectedDeleteThread;