diff --git a/lib/socket/socket.react.js b/lib/socket/socket.react.js --- a/lib/socket/socket.react.js +++ b/lib/socket/socket.react.js @@ -102,6 +102,8 @@ +dispatchActionPromise: DispatchActionPromise, // async functions that hit server APIs +logOut: (preRequestUserState: PreRequestUserState) => Promise, + +noDataAfterPolicyAcknowledgment?: boolean, + +refetchUserData?: () => Promise, }; type State = { +inflightRequests: ?InflightRequests, @@ -120,6 +122,7 @@ reopenConnectionAfterClosing: boolean = false; invalidationRecoveryInProgress: boolean = false; initializedWithUserState: ?PreRequestUserState; + failuresAfterPolicyAcknowledgment: number = 0; openSocket(newStatus: ConnectionStatus) { if ( @@ -403,6 +406,7 @@ if (!message) { return; } + this.failuresAfterPolicyAcknowledgment = 0; const { inflightRequests } = this.state; if (!inflightRequests) { @@ -630,6 +634,28 @@ try { await this.sendInitialMessage(); } catch (e) { + if (this.props.noDataAfterPolicyAcknowledgment) { + this.failuresAfterPolicyAcknowledgment++; + } else { + this.failuresAfterPolicyAcknowledgment = 0; + } + if ( + this.failuresAfterPolicyAcknowledgment >= 2 && + this.props.refetchUserData + ) { + this.failuresAfterPolicyAcknowledgment = 0; + try { + await this.props.refetchUserData(); + } catch (error) { + console.log(error); + this.props.dispatchActionPromise( + logOutActionTypes, + this.props.logOut(this.props.preRequestUserState), + ); + } + return; + } + console.log(e); const { status } = this.props.connection; if ( diff --git a/lib/types/account-types.js b/lib/types/account-types.js --- a/lib/types/account-types.js +++ b/lib/types/account-types.js @@ -87,6 +87,7 @@ logInFromWebForm: 'LOG_IN_FROM_WEB_FORM', logInFromNativeForm: 'LOG_IN_FROM_NATIVE_FORM', logInFromNativeSIWE: 'LOG_IN_FROM_NATIVE_SIWE', + refetchUserDataAfterAcknowledgment: 'REFETCH_USER_DATA_AFTER_ACKNOWLEDGMENT', }); export type LogInActionSource = $Values; diff --git a/native/selectors/account-selectors.js b/native/selectors/account-selectors.js --- a/native/selectors/account-selectors.js +++ b/native/selectors/account-selectors.js @@ -4,8 +4,12 @@ import { logInExtraInfoSelector } from 'lib/selectors/account-selectors'; import type { LogInExtraInfo } from 'lib/types/account-types'; +import type { UserPolicies } from 'lib/types/policy-types'; +import { values } from 'lib/utils/objects'; import { calendarActiveSelector } from '../navigation/nav-selectors'; +import type { AppState } from '../redux/state-types'; +import type { ConnectivityInfo } from '../types/connectivity'; import type { NavPlusRedux } from '../types/selector-types'; const nativeLogInExtraInfoSelector: ( @@ -19,4 +23,23 @@ ) => () => logInExtraInfoFunc(calendarActive), ); -export { nativeLogInExtraInfoSelector }; +const noDataAfterPolicyAcknowledgmentSelector: ( + state: AppState, +) => boolean = createSelector( + (state: AppState) => state.connectivity, + (state: AppState) => state.messageStore.currentAsOf, + (state: AppState) => state.userPolicies, + ( + connectivity: ConnectivityInfo, + currentAsOf: number, + userPolicies: UserPolicies, + ) => + connectivity.connected && + currentAsOf === 0 && + values(userPolicies).every(policy => policy.isAcknowledged), +); + +export { + nativeLogInExtraInfoSelector, + noDataAfterPolicyAcknowledgmentSelector, +}; diff --git a/native/socket.react.js b/native/socket.react.js --- a/native/socket.react.js +++ b/native/socket.react.js @@ -1,15 +1,19 @@ // @flow import * as React from 'react'; +import Alert from 'react-native/Libraries/Alert/Alert'; import { useDispatch } from 'react-redux'; -import { logOut } from 'lib/actions/user-actions'; +import { logOut, logOutActionTypes } from 'lib/actions/user-actions'; import { preRequestUserStateSelector } from 'lib/selectors/account-selectors'; import { isLoggedIn } from 'lib/selectors/user-selectors'; +import { accountHasPassword } from 'lib/shared/account-utils'; import Socket, { type BaseSocketProps } from 'lib/socket/socket.react'; +import { logInActionSources } from 'lib/types/account-types'; import { useServerCall, useDispatchActionPromise, + fetchNewCookieFromNativeCredentials, } from 'lib/utils/action-utils'; import { InputStateContext } from './input/input-state'; @@ -19,6 +23,7 @@ } from './navigation/nav-selectors'; import { NavContext } from './navigation/navigation-context'; import { useSelector } from './redux/redux-utils'; +import { noDataAfterPolicyAcknowledgmentSelector } from './selectors/account-selectors'; import { openSocketSelector, sessionIdentificationSelector, @@ -38,6 +43,10 @@ const active = useSelector( state => isLoggedIn(state) && state.lifecycleState !== 'background', ); + const noDataAfterPolicyAcknowledgment = useSelector( + noDataAfterPolicyAcknowledgmentSelector, + ); + const currentUserInfo = useSelector(state => state.currentUserInfo); const openSocket = useSelector(openSocketSelector); const sessionIdentification = useSelector(sessionIdentificationSelector); @@ -80,6 +89,36 @@ const dispatchActionPromise = useDispatchActionPromise(); const callLogOut = useServerCall(logOut); + const refetchUserData = React.useCallback(async () => { + if (!accountHasPassword(currentUserInfo)) { + dispatchActionPromise( + logOutActionTypes, + callLogOut(preRequestUserState), + ); + Alert.alert( + 'Log in needed', + 'After acknowledging the policies, we need you to log in to your account again', + [{ text: 'OK' }], + ); + return; + } + + await fetchNewCookieFromNativeCredentials( + dispatch, + cookie, + urlPrefix, + logInActionSources.refetchUserDataAfterAcknowledgment, + ); + }, [ + callLogOut, + cookie, + currentUserInfo, + dispatch, + dispatchActionPromise, + preRequestUserState, + urlPrefix, + ]); + return ( ); },