diff --git a/lib/actions/user-actions.js b/lib/actions/user-actions.js --- a/lib/actions/user-actions.js +++ b/lib/actions/user-actions.js @@ -25,6 +25,7 @@ KeyserverAuthRequest, ClientLogInResponse, KeyserverLogOutResult, + LogOutResult, } from '../types/account-types.js'; import type { UpdateUserAvatarRequest, @@ -66,6 +67,7 @@ import { getConfig } from '../utils/config.js'; import { useKeyserverCall } from '../utils/keyserver-call.js'; import { useSelector } from '../utils/redux-utils.js'; +import { usingCommServicesAccessToken } from '../utils/services-utils.js'; import sleep from '../utils/sleep.js'; import { ashoatKeyserverID } from '../utils/validation-utils.js'; @@ -188,21 +190,37 @@ ); } -const deleteIdentityAccountActionTypes = Object.freeze({ - started: 'DELETE_IDENTITY_ACCOUNT_STARTED', - success: 'DELETE_IDENTITY_ACCOUNT_SUCCESS', - failed: 'DELETE_IDENTITY_ACCOUNT_FAILED', +const deleteAccountActionTypes = Object.freeze({ + started: 'DELETE_ACCOUNT_STARTED', + success: 'DELETE_ACCOUNT_SUCCESS', + failed: 'DELETE_ACCOUNT_FAILED', }); -function useDeleteIdentityAccount(): () => Promise { +function useDeleteAccount(): ( + keyserverIDs?: $ReadOnlyArray, +) => Promise { const client = React.useContext(IdentityClientContext); const identityClient = client?.identityClient; - return React.useCallback(() => { - if (!identityClient) { - throw new Error('Identity service client is not initialized'); - } - return identityClient.deleteUser(); - }, [identityClient]); + + const preRequestUserState = useSelector(preRequestUserStateSelector); + const callKeyserverDeleteAccount = useKeyserverCall(deleteKeyserverAccount); + + return React.useCallback( + async (keyserverIDs?: $ReadOnlyArray) => { + if (usingCommServicesAccessToken) { + if (!identityClient) { + throw new Error('Identity service client is not initialized'); + } + await identityClient.deleteUser(); + } + const { keyserverIDs: _, ...result } = await callKeyserverDeleteAccount({ + preRequestUserState, + keyserverIDs, + }); + return result; + }, + [callKeyserverDeleteAccount, identityClient, preRequestUserState], + ); } const keyserverRegisterActionTypes = Object.freeze({ @@ -743,8 +761,8 @@ updateUserAvatar, resetUserStateActionType, setAccessTokenActionType, - deleteIdentityAccountActionTypes, - useDeleteIdentityAccount, + deleteAccountActionTypes, + useDeleteAccount, keyserverAuthActionTypes, useKeyserverAuth, identityRegisterActionTypes, diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js --- a/lib/types/redux-types.js +++ b/lib/types/redux-types.js @@ -234,18 +234,18 @@ +loadingInfo: LoadingInfo, } | { - +type: 'DELETE_IDENTITY_ACCOUNT_STARTED', + +type: 'DELETE_ACCOUNT_STARTED', +payload?: void, +loadingInfo: LoadingInfo, } | { - +type: 'DELETE_IDENTITY_ACCOUNT_FAILED', + +type: 'DELETE_ACCOUNT_FAILED', +error: true, +payload: Error, +loadingInfo: LoadingInfo, } | { - +type: 'DELETE_IDENTITY_ACCOUNT_SUCCESS', + +type: 'DELETE_ACCOUNT_SUCCESS', +payload: LogOutResult, +loadingInfo: LoadingInfo, } diff --git a/native/profile/delete-account.react.js b/native/profile/delete-account.react.js --- a/native/profile/delete-account.react.js +++ b/native/profile/delete-account.react.js @@ -5,31 +5,21 @@ import { ScrollView } from 'react-native-gesture-handler'; import { - deleteIdentityAccountActionTypes, - deleteKeyserverAccountActionTypes, - useDeleteIdentityAccount, - useDeleteKeyserverAccount, + deleteAccountActionTypes, + useDeleteAccount, } from 'lib/actions/user-actions.js'; -import { - createLoadingStatusSelector, - combineLoadingStatuses, -} from 'lib/selectors/loading-selectors.js'; +import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; -import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js'; import type { ProfileNavigationProp } from './profile.react.js'; -import { deleteNativeCredentialsFor } from '../account/native-credentials.js'; import Button from '../components/button.react.js'; import type { NavigationRoute } from '../navigation/route-names.js'; import { useSelector } from '../redux/redux-utils.js'; import { useStyles } from '../themes/colors.js'; import Alert from '../utils/alert.js'; -const keyserverLoadingStatusSelector = createLoadingStatusSelector( - deleteKeyserverAccountActionTypes, -); -const identityLoadingStatusSelector = createLoadingStatusSelector( - deleteIdentityAccountActionTypes, +const deleteAccountLoadingStatusSelector = createLoadingStatusSelector( + deleteAccountActionTypes, ); type Props = { @@ -38,20 +28,16 @@ }; const DeleteAccount: React.ComponentType = React.memo( function DeleteAccount() { - const keyserverLoadingStatus = useSelector(keyserverLoadingStatusSelector); - const identityLoadingStatus = useSelector(identityLoadingStatusSelector); - const combinedLoadingStatuses = combineLoadingStatuses( - keyserverLoadingStatus, - identityLoadingStatus, + const deleteAccountLoadingStatus = useSelector( + deleteAccountLoadingStatusSelector, ); const styles = useStyles(unboundStyles); const dispatchActionPromise = useDispatchActionPromise(); - const callDeleteKeyserverAccount = useDeleteKeyserverAccount(); - const callDeleteIdentityAccount = useDeleteIdentityAccount(); + const callDeleteAccount = useDeleteAccount(); - const isButtonDisabled = combinedLoadingStatuses === 'loading'; + const isButtonDisabled = deleteAccountLoadingStatus === 'loading'; const buttonContent = isButtonDisabled ? ( @@ -64,26 +50,9 @@ [styles.warningText, styles.lastWarningText], ); - const deleteKeyserverAction = React.useCallback(async () => { - try { - await deleteNativeCredentialsFor(); - return await callDeleteKeyserverAccount(); - } catch (e) { - Alert.alert( - 'Unknown error deleting keyserver account', - 'Uhh... try again?', - [{ text: 'OK' }], - { - cancelable: false, - }, - ); - throw e; - } - }, [callDeleteKeyserverAccount]); - - const deleteIdentityAction = React.useCallback(async () => { + const deleteAccountAction = React.useCallback(async () => { try { - return await callDeleteIdentityAccount(); + return await callDeleteAccount(); } catch (e) { Alert.alert( 'Unknown error deleting account', @@ -95,20 +64,14 @@ ); throw e; } - }, [callDeleteIdentityAccount]); + }, [callDeleteAccount]); const onDelete = React.useCallback(() => { void dispatchActionPromise( - deleteKeyserverAccountActionTypes, - deleteKeyserverAction(), + deleteAccountActionTypes, + deleteAccountAction(), ); - if (usingCommServicesAccessToken) { - void dispatchActionPromise( - deleteIdentityAccountActionTypes, - deleteIdentityAction(), - ); - } - }, [dispatchActionPromise, deleteKeyserverAction, deleteIdentityAction]); + }, [dispatchActionPromise, deleteAccountAction]); return ( = React.memo<{}>( function AccountDeleteModal(): React.Node { - const isDeleteKeyserverAccountLoading = useSelector( - state => deleteKeyserverAccountLoadingStatusSelector(state) === 'loading', - ); - const isDeleteIdentityAccountLoading = useSelector( + const inputDisabled = useSelector( state => deleteIdentityAccountLoadingStatusSelector(state) === 'loading', ); - const inputDisabled = - isDeleteKeyserverAccountLoading || isDeleteIdentityAccountLoading; - - const callDeleteIdentityAccount = useDeleteIdentityAccount(); - const callDeleteKeyserverAccount = useDeleteKeyserverAccount(); + const callDeleteIdentityAccount = useDeleteAccount(); const dispatchActionPromise = useDispatchActionPromise(); - const { popModal } = useModalContext(); - const [keyserverErrorMessage, setKeyserverErrorMessage] = - React.useState(''); - const [identityErrorMessage, setIdentityErrorMessage] = React.useState(''); - - const keyserverError = keyserverErrorMessage ? ( -

{keyserverErrorMessage}

- ) : null; - const identityError = identityErrorMessage ? ( -

{identityErrorMessage}

- ) : null; - let combinedErrorMessages; - if (keyserverError || identityError) { - combinedErrorMessages = ( + const [errorMessage, setErrorMessage] = React.useState(''); + let error; + if (errorMessage) { + error = (
- {keyserverError} - {identityError} +

{errorMessage}

); } - const deleteKeyserverAction = React.useCallback(async () => { - try { - setKeyserverErrorMessage(''); - const response = await callDeleteKeyserverAccount(); - // This check ensures that we don't call `popModal()` twice - if (!usingCommServicesAccessToken) { - popModal(); - } - return response; - } catch (e) { - setKeyserverErrorMessage( - 'unknown error deleting account from keyserver', - ); - throw e; - } - }, [callDeleteKeyserverAccount, popModal]); - const deleteIdentityAction = React.useCallback(async () => { try { - setIdentityErrorMessage(''); + setErrorMessage(''); const response = await callDeleteIdentityAccount(); popModal(); return response; } catch (e) { - setIdentityErrorMessage( - 'unknown error deleting account from identity service', - ); + setErrorMessage('unknown error deleting account'); throw e; } }, [callDeleteIdentityAccount, popModal]); @@ -99,17 +56,11 @@ (event: SyntheticEvent) => { event.preventDefault(); void dispatchActionPromise( - deleteKeyserverAccountActionTypes, - deleteKeyserverAction(), + deleteAccountActionTypes, + deleteIdentityAction(), ); - if (usingCommServicesAccessToken) { - void dispatchActionPromise( - deleteIdentityAccountActionTypes, - deleteIdentityAction(), - ); - } }, - [dispatchActionPromise, deleteKeyserverAction, deleteIdentityAction], + [dispatchActionPromise, deleteIdentityAction], ); return ( @@ -131,7 +82,7 @@ > Delete Account - {combinedErrorMessages} + {error}