diff --git a/native/account/fullscreen-siwe-panel.react.js b/native/account/fullscreen-siwe-panel.react.js
index 6121c3bd0..0f5b1c6c3 100644
--- a/native/account/fullscreen-siwe-panel.react.js
+++ b/native/account/fullscreen-siwe-panel.react.js
@@ -1,228 +1,207 @@
// @flow
import { useNavigation } from '@react-navigation/native';
import invariant from 'invariant';
import * as React from 'react';
import { ActivityIndicator, View } from 'react-native';
import { setDataLoadedActionType } from 'lib/actions/client-db-store-actions.js';
import { useWalletLogIn } from 'lib/hooks/login-hooks.js';
import { type SIWEResult, SIWEMessageTypes } from 'lib/types/siwe-types.js';
import { ServerError, getMessageForException } from 'lib/utils/errors.js';
import { useDispatch } from 'lib/utils/redux-utils.js';
import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js';
import { useGetEthereumAccountFromSIWEResult } from './registration/ethereum-utils.js';
import { RegistrationContext } from './registration/registration-context.js';
-import { enableNewRegistrationMode } from './registration/registration-types.js';
import { useLegacySIWEServerCall } from './siwe-hooks.js';
import SIWEPanel from './siwe-panel.react.js';
import { commRustModule } from '../native-modules.js';
import {
AccountDoesNotExistRouteName,
RegistrationRouteName,
} from '../navigation/route-names.js';
import {
unknownErrorAlertDetails,
appOutOfDateAlertDetails,
} from '../utils/alert-messages.js';
import Alert from '../utils/alert.js';
const siweSignatureRequestData = { messageType: SIWEMessageTypes.MSG_AUTH };
type Props = {
+goBackToPrompt: () => mixed,
+closing: boolean,
};
function FullscreenSIWEPanel(props: Props): React.Node {
const [loading, setLoading] = React.useState(true);
const activity = loading ? : null;
const activityContainer = React.useMemo(
() => ({
flex: 1,
}),
[],
);
const registrationContext = React.useContext(RegistrationContext);
invariant(registrationContext, 'registrationContext should be set');
- const { setSkipEthereumLoginOnce, register: registrationServerCall } =
- registrationContext;
+ const { setSkipEthereumLoginOnce } = registrationContext;
const getEthereumAccountFromSIWEResult =
useGetEthereumAccountFromSIWEResult();
const { navigate } = useNavigation();
const { goBackToPrompt } = props;
const onAccountDoesNotExist = React.useCallback(
async (result: SIWEResult) => {
await getEthereumAccountFromSIWEResult(result);
setSkipEthereumLoginOnce(true);
goBackToPrompt();
navigate<'Registration'>(RegistrationRouteName, {
screen: AccountDoesNotExistRouteName,
});
},
[
getEthereumAccountFromSIWEResult,
navigate,
goBackToPrompt,
setSkipEthereumLoginOnce,
],
);
const onNonceExpired = React.useCallback(
(registrationOrLogin: 'registration' | 'login') => {
Alert.alert(
registrationOrLogin === 'registration'
? 'Registration attempt timed out'
: 'Login attempt timed out',
'Please try again',
[{ text: 'OK', onPress: goBackToPrompt }],
{ cancelable: false },
);
},
[goBackToPrompt],
);
const legacySiweServerCall = useLegacySIWEServerCall();
const walletLogIn = useWalletLogIn();
const successRef = React.useRef(false);
const dispatch = useDispatch();
const onSuccess = React.useCallback(
async (result: SIWEResult) => {
successRef.current = true;
if (usingCommServicesAccessToken) {
try {
const findUserIDResponseString =
await commRustModule.findUserIDForWalletAddress(result.address);
const findUserIDResponse = JSON.parse(findUserIDResponseString);
if (findUserIDResponse.userID || findUserIDResponse.isReserved) {
try {
await walletLogIn(
result.address,
result.message,
result.signature,
);
} catch (e) {
const messageForException = getMessageForException(e);
if (messageForException === 'nonce_expired') {
onNonceExpired('login');
} else if (
messageForException === 'unsupported_version' ||
messageForException === 'client_version_unsupported'
) {
Alert.alert(
appOutOfDateAlertDetails.title,
appOutOfDateAlertDetails.message,
[{ text: 'OK', onPress: goBackToPrompt }],
{ cancelable: false },
);
} else {
throw e;
}
}
- } else if (enableNewRegistrationMode) {
- await onAccountDoesNotExist(result);
} else {
- try {
- await registrationServerCall({
- farcasterID: null,
- accountSelection: {
- accountType: 'ethereum',
- ...result,
- avatarURI: null,
- },
- avatarData: null,
- clearCachedSelections: () => {},
- onNonceExpired: () => onNonceExpired('registration'),
- onAlertAcknowledged: goBackToPrompt,
- });
- } catch {
- // We swallow exceptions here because registrationServerCall
- // already handles showing Alerts, and we don't want to show two
- }
+ await onAccountDoesNotExist(result);
}
} catch (e) {
Alert.alert(
unknownErrorAlertDetails.title,
unknownErrorAlertDetails.message,
[{ text: 'OK', onPress: goBackToPrompt }],
{ cancelable: false },
);
}
} else {
try {
await legacySiweServerCall({
...result,
- doNotRegister: enableNewRegistrationMode,
+ doNotRegister: true,
});
} catch (e) {
if (
e instanceof ServerError &&
e.message === 'account_does_not_exist'
) {
await onAccountDoesNotExist(result);
} else if (
e instanceof ServerError &&
e.message === 'client_version_unsupported'
) {
Alert.alert(
appOutOfDateAlertDetails.title,
appOutOfDateAlertDetails.message,
[{ text: 'OK', onPress: goBackToPrompt }],
{ cancelable: false },
);
} else {
Alert.alert(
unknownErrorAlertDetails.title,
unknownErrorAlertDetails.message,
[{ text: 'OK', onPress: goBackToPrompt }],
{ cancelable: false },
);
}
return;
}
dispatch({
type: setDataLoadedActionType,
payload: {
dataLoaded: true,
},
});
}
},
[
walletLogIn,
- registrationServerCall,
goBackToPrompt,
dispatch,
legacySiweServerCall,
onAccountDoesNotExist,
onNonceExpired,
],
);
const ifBeforeSuccessGoBackToPrompt = React.useCallback(() => {
if (!successRef.current) {
goBackToPrompt();
}
}, [goBackToPrompt]);
const { closing } = props;
return (
<>
{activity}
>
);
}
export default FullscreenSIWEPanel;
diff --git a/native/account/legacy-register-panel.react.js b/native/account/legacy-register-panel.react.js
deleted file mode 100644
index 1016ac585..000000000
--- a/native/account/legacy-register-panel.react.js
+++ /dev/null
@@ -1,508 +0,0 @@
-// @flow
-
-import invariant from 'invariant';
-import * as React from 'react';
-import {
- Text,
- View,
- StyleSheet,
- Platform,
- Keyboard,
- Linking,
-} from 'react-native';
-
-import { setDataLoadedActionType } from 'lib/actions/client-db-store-actions.js';
-import {
- legacyKeyserverRegisterActionTypes,
- legacyKeyserverRegister,
- getOlmSessionInitializationDataActionTypes,
-} from 'lib/actions/user-actions.js';
-import { useLegacyAshoatKeyserverCall } from 'lib/keyserver-conn/legacy-keyserver-call.js';
-import {
- createLoadingStatusSelector,
- combineLoadingStatuses,
-} from 'lib/selectors/loading-selectors.js';
-import { validUsernameRegex } from 'lib/shared/account-utils.js';
-import { useInitialNotificationsEncryptedMessage } from 'lib/shared/crypto-utils.js';
-import type {
- LegacyRegisterInfo,
- LegacyLogInExtraInfo,
- LegacyRegisterResult,
- LegacyLogInStartingPayload,
-} from 'lib/types/account-types.js';
-import type { LoadingStatus } from 'lib/types/loading-types.js';
-import type { Dispatch } from 'lib/types/redux-types.js';
-import {
- useDispatchActionPromise,
- type DispatchActionPromise,
-} from 'lib/utils/redux-promise-utils.js';
-import { useDispatch } from 'lib/utils/redux-utils.js';
-
-import { TextInput } from './modal-components.react.js';
-import { setNativeCredentials } from './native-credentials.js';
-import { PanelButton, Panel } from './panel-components.react.js';
-import { authoritativeKeyserverID } from '../authoritative-keyserver.js';
-import SWMansionIcon from '../components/swmansion-icon.react.js';
-import { useSelector } from '../redux/redux-utils.js';
-import { nativeLegacyLogInExtraInfoSelector } from '../selectors/account-selectors.js';
-import type { KeyPressEvent } from '../types/react-native.js';
-import type { ViewStyle } from '../types/styles.js';
-import {
- appOutOfDateAlertDetails,
- usernameReservedAlertDetails,
- usernameTakenAlertDetails,
- unknownErrorAlertDetails,
-} from '../utils/alert-messages.js';
-import Alert from '../utils/alert.js';
-import { type StateContainer } from '../utils/state-container.js';
-
-type WritableLegacyRegisterState = {
- usernameInputText: string,
- passwordInputText: string,
- confirmPasswordInputText: string,
-};
-export type LegacyRegisterState = $ReadOnly;
-type BaseProps = {
- +setActiveAlert: (activeAlert: boolean) => void,
- +opacityStyle: ViewStyle,
- +legacyRegisterState: StateContainer,
-};
-type Props = {
- ...BaseProps,
- +loadingStatus: LoadingStatus,
- +legacyLogInExtraInfo: () => Promise,
- +dispatch: Dispatch,
- +dispatchActionPromise: DispatchActionPromise,
- +legacyRegister: (
- registerInfo: LegacyRegisterInfo,
- ) => Promise,
- +getInitialNotificationsEncryptedMessage: () => Promise,
-};
-type State = {
- +confirmPasswordFocused: boolean,
-};
-class LegacyRegisterPanel extends React.PureComponent {
- state: State = {
- confirmPasswordFocused: false,
- };
- usernameInput: ?TextInput;
- passwordInput: ?TextInput;
- confirmPasswordInput: ?TextInput;
- passwordBeingAutoFilled = false;
-
- render(): React.Node {
- let confirmPasswordTextInputExtraProps;
- if (
- Platform.OS !== 'ios' ||
- this.state.confirmPasswordFocused ||
- this.props.legacyRegisterState.state.confirmPasswordInputText.length > 0
- ) {
- confirmPasswordTextInputExtraProps = {
- secureTextEntry: true,
- textContentType: 'password',
- };
- }
-
- let onPasswordKeyPress;
- if (Platform.OS === 'ios') {
- onPasswordKeyPress = this.onPasswordKeyPress;
- }
-
- const privatePolicyNotice = (
-
-
- By signing up, you agree to our{' '}
-
- Terms
-
- {' & '}
-
- Privacy Policy
-
- .
-
-
- );
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
- {privatePolicyNotice}
-
-
-
- );
- }
-
- usernameInputRef = (usernameInput: ?TextInput) => {
- this.usernameInput = usernameInput;
- };
-
- passwordInputRef = (passwordInput: ?TextInput) => {
- this.passwordInput = passwordInput;
- };
-
- confirmPasswordInputRef = (confirmPasswordInput: ?TextInput) => {
- this.confirmPasswordInput = confirmPasswordInput;
- };
-
- focusUsernameInput = () => {
- invariant(this.usernameInput, 'ref should be set');
- this.usernameInput.focus();
- };
-
- focusPasswordInput = () => {
- invariant(this.passwordInput, 'ref should be set');
- this.passwordInput.focus();
- };
-
- focusConfirmPasswordInput = () => {
- invariant(this.confirmPasswordInput, 'ref should be set');
- this.confirmPasswordInput.focus();
- };
-
- onTermsOfUsePressed = () => {
- void Linking.openURL('https://comm.app/terms');
- };
-
- onPrivacyPolicyPressed = () => {
- void Linking.openURL('https://comm.app/privacy');
- };
-
- onChangeUsernameInputText = (text: string) => {
- this.props.legacyRegisterState.setState({ usernameInputText: text });
- };
-
- onChangePasswordInputText = (text: string) => {
- const stateUpdate: Partial = {};
- stateUpdate.passwordInputText = text;
- if (this.passwordBeingAutoFilled) {
- this.passwordBeingAutoFilled = false;
- stateUpdate.confirmPasswordInputText = text;
- }
- this.props.legacyRegisterState.setState(stateUpdate);
- };
-
- onPasswordKeyPress = (event: KeyPressEvent) => {
- const { key } = event.nativeEvent;
- if (
- key.length > 1 &&
- key !== 'Backspace' &&
- key !== 'Enter' &&
- this.props.legacyRegisterState.state.confirmPasswordInputText.length === 0
- ) {
- this.passwordBeingAutoFilled = true;
- }
- };
-
- onChangeConfirmPasswordInputText = (text: string) => {
- this.props.legacyRegisterState.setState({ confirmPasswordInputText: text });
- };
-
- onConfirmPasswordFocus = () => {
- this.setState({ confirmPasswordFocused: true });
- };
-
- onSubmit = async () => {
- this.props.setActiveAlert(true);
- if (this.props.legacyRegisterState.state.passwordInputText === '') {
- Alert.alert(
- 'Empty password',
- 'Password cannot be empty',
- [{ text: 'OK', onPress: this.onPasswordAlertAcknowledged }],
- { cancelable: false },
- );
- } else if (
- this.props.legacyRegisterState.state.passwordInputText !==
- this.props.legacyRegisterState.state.confirmPasswordInputText
- ) {
- Alert.alert(
- 'Passwords don’t match',
- 'Password fields must contain the same password',
- [{ text: 'OK', onPress: this.onPasswordAlertAcknowledged }],
- { cancelable: false },
- );
- } else if (
- this.props.legacyRegisterState.state.usernameInputText.search(
- validUsernameRegex,
- ) === -1
- ) {
- Alert.alert(
- 'Invalid username',
- 'Usernames must be at least six characters long, start with either a ' +
- 'letter or a number, and may contain only letters, numbers, or the ' +
- 'characters “-” and “_”',
- [{ text: 'OK', onPress: this.onUsernameAlertAcknowledged }],
- { cancelable: false },
- );
- } else {
- Keyboard.dismiss();
- const extraInfo = await this.props.legacyLogInExtraInfo();
- const initialNotificationsEncryptedMessage =
- await this.props.getInitialNotificationsEncryptedMessage();
- void this.props.dispatchActionPromise(
- legacyKeyserverRegisterActionTypes,
- this.legacyRegisterAction({
- ...extraInfo,
- initialNotificationsEncryptedMessage,
- }),
- undefined,
- ({
- calendarQuery: extraInfo.calendarQuery,
- }: LegacyLogInStartingPayload),
- );
- }
- };
-
- onPasswordAlertAcknowledged = () => {
- this.props.setActiveAlert(false);
- this.props.legacyRegisterState.setState(
- {
- passwordInputText: '',
- confirmPasswordInputText: '',
- },
- () => {
- invariant(this.passwordInput, 'ref should exist');
- this.passwordInput.focus();
- },
- );
- };
-
- onUsernameAlertAcknowledged = () => {
- this.props.setActiveAlert(false);
- this.props.legacyRegisterState.setState(
- {
- usernameInputText: '',
- },
- () => {
- invariant(this.usernameInput, 'ref should exist');
- this.usernameInput.focus();
- },
- );
- };
-
- async legacyRegisterAction(
- extraInfo: LegacyLogInExtraInfo,
- ): Promise {
- try {
- const result = await this.props.legacyRegister({
- ...extraInfo,
- username: this.props.legacyRegisterState.state.usernameInputText,
- password: this.props.legacyRegisterState.state.passwordInputText,
- });
- this.props.setActiveAlert(false);
- this.props.dispatch({
- type: setDataLoadedActionType,
- payload: {
- dataLoaded: true,
- },
- });
- await setNativeCredentials({
- username: result.currentUserInfo.username,
- password: this.props.legacyRegisterState.state.passwordInputText,
- });
- return result;
- } catch (e) {
- if (e.message === 'username_reserved') {
- Alert.alert(
- usernameReservedAlertDetails.title,
- usernameReservedAlertDetails.message,
- [{ text: 'OK', onPress: this.onUsernameAlertAcknowledged }],
- { cancelable: false },
- );
- } else if (e.message === 'username_taken') {
- Alert.alert(
- usernameTakenAlertDetails.title,
- usernameTakenAlertDetails.message,
- [{ text: 'OK', onPress: this.onUsernameAlertAcknowledged }],
- { cancelable: false },
- );
- } else if (e.message === 'client_version_unsupported') {
- Alert.alert(
- appOutOfDateAlertDetails.title,
- appOutOfDateAlertDetails.message,
- [{ text: 'OK', onPress: this.onOtherErrorAlertAcknowledged }],
- { cancelable: false },
- );
- } else {
- Alert.alert(
- unknownErrorAlertDetails.title,
- unknownErrorAlertDetails.message,
- [{ text: 'OK', onPress: this.onOtherErrorAlertAcknowledged }],
- { cancelable: false },
- );
- }
- throw e;
- }
- }
-
- onOtherErrorAlertAcknowledged = () => {
- this.props.setActiveAlert(false);
- };
-}
-
-const styles = StyleSheet.create({
- container: {
- zIndex: 2,
- },
- footer: {
- alignItems: 'stretch',
- flexDirection: 'row',
- flexShrink: 1,
- justifyContent: 'space-between',
- paddingLeft: 24,
- },
- hyperlinkText: {
- color: '#036AFF',
- fontWeight: 'bold',
- },
- icon: {
- bottom: 10,
- left: 4,
- position: 'absolute',
- },
- input: {
- paddingLeft: 35,
- },
- notice: {
- alignSelf: 'center',
- display: 'flex',
- flexShrink: 1,
- maxWidth: 190,
- paddingBottom: 18,
- paddingRight: 8,
- paddingTop: 12,
- },
- noticeText: {
- color: '#444',
- fontSize: 13,
- lineHeight: 20,
- textAlign: 'center',
- },
- row: {
- marginHorizontal: 24,
- },
-});
-
-const registerLoadingStatusSelector = createLoadingStatusSelector(
- legacyKeyserverRegisterActionTypes,
-);
-const olmSessionInitializationDataLoadingStatusSelector =
- createLoadingStatusSelector(getOlmSessionInitializationDataActionTypes);
-
-const ConnectedLegacyRegisterPanel: React.ComponentType =
- React.memo(function ConnectedLegacyRegisterPanel(
- props: BaseProps,
- ) {
- const registerLoadingStatus = useSelector(registerLoadingStatusSelector);
- const olmSessionInitializationDataLoadingStatus = useSelector(
- olmSessionInitializationDataLoadingStatusSelector,
- );
- const loadingStatus = combineLoadingStatuses(
- registerLoadingStatus,
- olmSessionInitializationDataLoadingStatus,
- );
-
- const legacyLogInExtraInfo = useSelector(
- nativeLegacyLogInExtraInfoSelector,
- );
-
- const dispatch = useDispatch();
- const dispatchActionPromise = useDispatchActionPromise();
- const callLegacyRegister = useLegacyAshoatKeyserverCall(
- legacyKeyserverRegister,
- );
- const getInitialNotificationsEncryptedMessage =
- useInitialNotificationsEncryptedMessage(authoritativeKeyserverID);
-
- return (
-
- );
- });
-
-export default ConnectedLegacyRegisterPanel;
diff --git a/native/account/logged-out-modal.react.js b/native/account/logged-out-modal.react.js
index 67920f62f..adf96643b 100644
--- a/native/account/logged-out-modal.react.js
+++ b/native/account/logged-out-modal.react.js
@@ -1,723 +1,657 @@
// @flow
import Icon from '@expo/vector-icons/FontAwesome.js';
import * as React from 'react';
import {
View,
Text,
TouchableOpacity,
Image,
Keyboard,
Platform,
BackHandler,
ActivityIndicator,
} from 'react-native';
import {
Easing,
useSharedValue,
withTiming,
useAnimatedStyle,
runOnJS,
} from 'react-native-reanimated';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useIsLoggedInToAuthoritativeKeyserver } from 'lib/hooks/account-hooks.js';
import { setActiveSessionRecoveryActionType } from 'lib/keyserver-conn/keyserver-conn-types.js';
import { isLoggedIn } from 'lib/selectors/user-selectors.js';
import { recoveryFromReduxActionSources } from 'lib/types/account-types.js';
import { useDispatch } from 'lib/utils/redux-utils.js';
import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js';
import { splashBackgroundURI } from './background-info.js';
import FullscreenSIWEPanel from './fullscreen-siwe-panel.react.js';
-import LegacyRegisterPanel from './legacy-register-panel.react.js';
-import type { LegacyRegisterState } from './legacy-register-panel.react.js';
import LogInPanel from './log-in-panel.react.js';
import type { LogInState } from './log-in-panel.react.js';
import LoggedOutStaffInfo from './logged-out-staff-info.react.js';
-import { enableNewRegistrationMode } from './registration/registration-types.js';
import { authoritativeKeyserverID } from '../authoritative-keyserver.js';
import KeyboardAvoidingView from '../components/keyboard-avoiding-view.react.js';
import ConnectedStatusBar from '../connected-status-bar.react.js';
import { useRatchetingKeyboardHeight } from '../keyboard/animated-keyboard.js';
import { createIsForegroundSelector } from '../navigation/nav-selectors.js';
import { NavContext } from '../navigation/navigation-context.js';
import type { RootNavigationProp } from '../navigation/root-navigator.react.js';
import {
type NavigationRoute,
LoggedOutModalRouteName,
RegistrationRouteName,
QRCodeSignInNavigatorRouteName,
} from '../navigation/route-names.js';
import { useSelector } from '../redux/redux-utils.js';
import { usePersistedStateLoaded } from '../selectors/app-state-selectors.js';
import { derivedDimensionsInfoSelector } from '../selectors/dimensions-selectors.js';
import { splashStyleSelector } from '../splash.js';
import { useStyles } from '../themes/colors.js';
import { AnimatedView } from '../types/styles.js';
import EthereumLogo from '../vectors/ethereum-logo.react.js';
let initialAppLoad = true;
const safeAreaEdges = ['top', 'bottom'];
-export type LoggedOutMode =
- | 'loading'
- | 'prompt'
- | 'log-in'
- | 'register'
- | 'siwe';
+export type LoggedOutMode = 'loading' | 'prompt' | 'log-in' | 'siwe';
const timingConfig = {
duration: 250,
easing: Easing.out(Easing.ease),
};
// prettier-ignore
function getPanelPaddingTop(
modeValue /*: string */,
keyboardHeightValue /*: number */,
contentHeightValue /*: number */,
) /*: number */ {
'worklet';
const headerHeight = Platform.OS === 'ios' ? 62.33 : 58.54;
let containerSize = headerHeight;
if (modeValue === 'loading' || modeValue === 'prompt') {
containerSize += Platform.OS === 'ios' ? 40 : 61;
} else if (modeValue === 'log-in') {
containerSize += 140;
- } else if (modeValue === 'register') {
- containerSize += Platform.OS === 'ios' ? 181 : 180;
} else if (modeValue === 'siwe') {
containerSize += 250;
}
const freeSpace = contentHeightValue - keyboardHeightValue - containerSize;
const targetPanelPaddingTop = Math.max(freeSpace, 0) / 2;
return withTiming(targetPanelPaddingTop, timingConfig);
}
// prettier-ignore
function getPanelOpacity(
modeValue /*: string */,
finishResettingToPrompt/*: () => void */,
) /*: number */ {
'worklet';
const targetPanelOpacity =
modeValue === 'loading' || modeValue === 'prompt' ? 0 : 1;
return withTiming(
targetPanelOpacity,
timingConfig,
(succeeded /*?: boolean */) => {
if (succeeded && targetPanelOpacity === 0) {
runOnJS(finishResettingToPrompt)();
}
},
);
}
const unboundStyles = {
animationContainer: {
flex: 1,
},
backButton: {
position: 'absolute',
top: 13,
},
button: {
borderRadius: 4,
marginBottom: 4,
marginTop: 4,
marginLeft: 4,
marginRight: 4,
paddingBottom: 14,
paddingLeft: 18,
paddingRight: 18,
paddingTop: 14,
flex: 1,
},
buttonContainer: {
bottom: 0,
left: 0,
marginLeft: 26,
marginRight: 26,
paddingBottom: 20,
position: 'absolute',
right: 0,
},
buttonText: {
fontFamily: 'OpenSans-Semibold',
fontSize: 17,
textAlign: 'center',
},
classicAuthButton: {
backgroundColor: 'purpleButton',
},
classicAuthButtonText: {
color: 'whiteText',
},
registerButtons: {
flexDirection: 'row',
},
signInButtons: {
flexDirection: 'row',
},
container: {
backgroundColor: 'transparent',
flex: 1,
},
header: {
color: 'white',
fontFamily: Platform.OS === 'ios' ? 'IBMPlexSans' : 'IBMPlexSans-Medium',
fontSize: 56,
fontWeight: '500',
lineHeight: 66,
textAlign: 'center',
},
loadingIndicator: {
paddingTop: 15,
},
modalBackground: {
bottom: 0,
left: 0,
position: 'absolute',
right: 0,
top: 0,
},
siweButton: {
backgroundColor: 'siweButton',
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
},
siweButtonText: {
color: 'siweButtonText',
},
siweOr: {
flex: 1,
flexDirection: 'row',
marginBottom: 18,
marginTop: 14,
},
siweOrLeftHR: {
borderColor: 'logInSpacer',
borderTopWidth: 1,
flex: 1,
marginRight: 18,
marginTop: 10,
},
siweOrRightHR: {
borderColor: 'logInSpacer',
borderTopWidth: 1,
flex: 1,
marginLeft: 18,
marginTop: 10,
},
siweOrText: {
color: 'whiteText',
fontSize: 17,
textAlign: 'center',
},
siweIcon: {
paddingRight: 10,
},
};
const isForegroundSelector = createIsForegroundSelector(
LoggedOutModalRouteName,
);
const backgroundSource = { uri: splashBackgroundURI };
const initialLogInState = {
usernameInputText: null,
passwordInputText: null,
};
-const initialLegacyRegisterState = {
- usernameInputText: '',
- passwordInputText: '',
- confirmPasswordInputText: '',
-};
type Mode = {
+curMode: LoggedOutMode,
+nextMode: LoggedOutMode,
};
type Props = {
+navigation: RootNavigationProp<'LoggedOutModal'>,
+route: NavigationRoute<'LoggedOutModal'>,
};
function LoggedOutModal(props: Props) {
const mountedRef = React.useRef(false);
React.useEffect(() => {
mountedRef.current = true;
return () => {
mountedRef.current = false;
};
}, []);
const [logInState, baseSetLogInState] =
React.useState(initialLogInState);
const setLogInState = React.useCallback(
(newLogInState: Partial) => {
if (!mountedRef.current) {
return;
}
baseSetLogInState(prevLogInState => ({
...prevLogInState,
...newLogInState,
}));
},
[],
);
const logInStateContainer = React.useMemo(
() => ({
state: logInState,
setState: setLogInState,
}),
[logInState, setLogInState],
);
- const [legacyRegisterState, baseSetLegacyRegisterState] =
- React.useState(initialLegacyRegisterState);
- const setLegacyRegisterState = React.useCallback(
- (newLegacyRegisterState: Partial) => {
- if (!mountedRef.current) {
- return;
- }
- baseSetLegacyRegisterState(prevLegacyRegisterState => ({
- ...prevLegacyRegisterState,
- ...newLegacyRegisterState,
- }));
- },
- [],
- );
- const legacyRegisterStateContainer = React.useMemo(
- () => ({
- state: legacyRegisterState,
- setState: setLegacyRegisterState,
- }),
- [legacyRegisterState, setLegacyRegisterState],
- );
-
const persistedStateLoaded = usePersistedStateLoaded();
const initialMode = persistedStateLoaded ? 'prompt' : 'loading';
const [mode, baseSetMode] = React.useState(() => ({
curMode: initialMode,
nextMode: initialMode,
}));
const setMode = React.useCallback((newMode: Partial) => {
if (!mountedRef.current) {
return;
}
baseSetMode(prevMode => ({
...prevMode,
...newMode,
}));
}, []);
const nextModeRef = React.useRef(initialMode);
const dimensions = useSelector(derivedDimensionsInfoSelector);
const contentHeight = useSharedValue(dimensions.safeAreaHeight);
const modeValue = useSharedValue(initialMode);
const buttonOpacity = useSharedValue(persistedStateLoaded ? 1 : 0);
const onPrompt = mode.curMode === 'prompt';
const prevOnPromptRef = React.useRef(onPrompt);
React.useEffect(() => {
if (onPrompt && !prevOnPromptRef.current) {
buttonOpacity.value = withTiming(1, {
easing: Easing.out(Easing.ease),
});
}
prevOnPromptRef.current = onPrompt;
}, [onPrompt, buttonOpacity]);
const curContentHeight = dimensions.safeAreaHeight;
const prevContentHeightRef = React.useRef(curContentHeight);
React.useEffect(() => {
if (curContentHeight === prevContentHeightRef.current) {
return;
}
prevContentHeightRef.current = curContentHeight;
contentHeight.value = curContentHeight;
}, [curContentHeight, contentHeight]);
const combinedSetMode = React.useCallback(
(newMode: LoggedOutMode) => {
nextModeRef.current = newMode;
setMode({ curMode: newMode, nextMode: newMode });
modeValue.value = newMode;
},
[setMode, modeValue],
);
const goBackToPrompt = React.useCallback(() => {
nextModeRef.current = 'prompt';
setMode({ nextMode: 'prompt' });
modeValue.value = 'prompt';
Keyboard.dismiss();
}, [setMode, modeValue]);
const loadingCompleteRef = React.useRef(persistedStateLoaded);
React.useEffect(() => {
if (!loadingCompleteRef.current && persistedStateLoaded) {
combinedSetMode('prompt');
loadingCompleteRef.current = true;
}
}, [persistedStateLoaded, combinedSetMode]);
const [activeAlert, setActiveAlert] = React.useState(false);
const navContext = React.useContext(NavContext);
const isForeground = isForegroundSelector(navContext);
const ratchetingKeyboardHeightInput = React.useMemo(
() => ({
ignoreKeyboardDismissal: activeAlert,
disabled: !isForeground,
}),
[activeAlert, isForeground],
);
const keyboardHeightValue = useRatchetingKeyboardHeight(
ratchetingKeyboardHeightInput,
);
// We remove the password from the TextInput on iOS before dismissing it,
// because otherwise iOS will prompt the user to save the password if the
// iCloud password manager is enabled. We'll put the password back after the
// dismissal concludes.
const temporarilyHiddenPassword = React.useRef();
const curLogInPassword = logInState.passwordInputText;
const resetToPrompt = React.useCallback(() => {
if (nextModeRef.current === 'prompt') {
return false;
}
if (Platform.OS === 'ios' && curLogInPassword) {
temporarilyHiddenPassword.current = curLogInPassword;
setLogInState({ passwordInputText: null });
}
goBackToPrompt();
return true;
}, [goBackToPrompt, curLogInPassword, setLogInState]);
const finishResettingToPrompt = React.useCallback(() => {
setMode({ curMode: nextModeRef.current });
if (temporarilyHiddenPassword.current) {
setLogInState({ passwordInputText: temporarilyHiddenPassword.current });
temporarilyHiddenPassword.current = null;
}
}, [setMode, setLogInState]);
React.useEffect(() => {
if (!isForeground) {
return undefined;
}
BackHandler.addEventListener('hardwareBackPress', resetToPrompt);
return () => {
BackHandler.removeEventListener('hardwareBackPress', resetToPrompt);
};
}, [isForeground, resetToPrompt]);
const rehydrateConcluded = useSelector(
state => !!(state._persist && state._persist.rehydrated && navContext),
);
const isLoggedInToAuthKeyserver = useIsLoggedInToAuthoritativeKeyserver();
const loggedIn = useSelector(isLoggedIn);
const dispatch = useDispatch();
React.useEffect(() => {
// This gets triggered when an app is killed and restarted
// Not when it is returned from being backgrounded
if (!initialAppLoad || !rehydrateConcluded) {
return;
}
initialAppLoad = false;
if (usingCommServicesAccessToken || __DEV__) {
return;
}
if (loggedIn === isLoggedInToAuthKeyserver) {
return;
}
const actionSource = loggedIn
? recoveryFromReduxActionSources.appStartReduxLoggedInButInvalidCookie
: recoveryFromReduxActionSources.appStartCookieLoggedInButInvalidRedux;
dispatch({
type: setActiveSessionRecoveryActionType,
payload: {
activeSessionRecovery: actionSource,
keyserverID: authoritativeKeyserverID,
},
});
}, [rehydrateConcluded, loggedIn, isLoggedInToAuthKeyserver, dispatch]);
const onPressSIWE = React.useCallback(() => {
combinedSetMode('siwe');
}, [combinedSetMode]);
const onPressLogIn = React.useCallback(() => {
combinedSetMode('log-in');
}, [combinedSetMode]);
const { navigate } = props.navigation;
const onPressQRCodeSignIn = React.useCallback(() => {
navigate(QRCodeSignInNavigatorRouteName);
}, [navigate]);
- const onPressRegister = React.useCallback(() => {
- combinedSetMode('register');
- }, [combinedSetMode]);
-
const onPressNewRegister = React.useCallback(() => {
navigate(RegistrationRouteName);
}, [navigate]);
const opacityStyle = useAnimatedStyle(() => ({
opacity: getPanelOpacity(modeValue.value, finishResettingToPrompt),
}));
const styles = useStyles(unboundStyles);
const panel = React.useMemo(() => {
if (mode.curMode === 'log-in') {
return (
);
- } else if (mode.curMode === 'register') {
- return (
-
- );
} else if (mode.curMode === 'loading') {
return (
);
}
return null;
}, [
mode.curMode,
setActiveAlert,
opacityStyle,
logInStateContainer,
- legacyRegisterStateContainer,
styles.loadingIndicator,
]);
const classicAuthButtonStyle = React.useMemo(
() => [styles.button, styles.classicAuthButton],
[styles.button, styles.classicAuthButton],
);
const classicAuthButtonTextStyle = React.useMemo(
() => [styles.buttonText, styles.classicAuthButtonText],
[styles.buttonText, styles.classicAuthButtonText],
);
const siweAuthButtonStyle = React.useMemo(
() => [styles.button, styles.siweButton],
[styles.button, styles.siweButton],
);
const siweAuthButtonTextStyle = React.useMemo(
() => [styles.buttonText, styles.siweButtonText],
[styles.buttonText, styles.siweButtonText],
);
const buttonsViewOpacity = useAnimatedStyle(() => ({
opacity: buttonOpacity.value,
}));
const buttonsViewStyle = React.useMemo(
() => [styles.buttonContainer, buttonsViewOpacity],
[styles.buttonContainer, buttonsViewOpacity],
);
const buttons = React.useMemo(() => {
if (mode.curMode !== 'prompt') {
return null;
}
- const registerButtons = [];
- registerButtons.push(
-
- Register
- ,
- );
- if (enableNewRegistrationMode) {
- registerButtons.push(
-
- Register (new)
- ,
- );
- }
-
const signInButtons = [];
signInButtons.push(
Sign in
,
);
if (__DEV__) {
signInButtons.push(
Sign in (QR)
,
);
}
return (
Sign in with Ethereum
or
{signInButtons}
- {registerButtons}
+
+
+ Register
+
+
);
}, [
mode.curMode,
- onPressRegister,
onPressNewRegister,
onPressLogIn,
onPressQRCodeSignIn,
onPressSIWE,
classicAuthButtonStyle,
classicAuthButtonTextStyle,
siweAuthButtonStyle,
siweAuthButtonTextStyle,
buttonsViewStyle,
styles.siweIcon,
styles.siweOr,
styles.siweOrLeftHR,
styles.siweOrText,
styles.siweOrRightHR,
styles.signInButtons,
styles.registerButtons,
]);
const windowWidth = dimensions.width;
const backButtonStyle = React.useMemo(
() => [
styles.backButton,
opacityStyle,
{ left: windowWidth < 360 ? 28 : 40 },
],
[styles.backButton, opacityStyle, windowWidth],
);
const paddingTopStyle = useAnimatedStyle(() => ({
paddingTop: getPanelPaddingTop(
modeValue.value,
keyboardHeightValue.value,
contentHeight.value,
),
}));
const animatedContentStyle = React.useMemo(
() => [styles.animationContainer, paddingTopStyle],
[styles.animationContainer, paddingTopStyle],
);
const animatedContent = React.useMemo(
() => (
Comm
{panel}
),
[
animatedContentStyle,
styles.header,
backButtonStyle,
resetToPrompt,
panel,
],
);
const curModeIsSIWE = mode.curMode === 'siwe';
const nextModeIsPrompt = mode.nextMode === 'prompt';
const siwePanel = React.useMemo(() => {
if (!curModeIsSIWE) {
return null;
}
return (
);
}, [curModeIsSIWE, goBackToPrompt, nextModeIsPrompt]);
const splashStyle = useSelector(splashStyleSelector);
const backgroundStyle = React.useMemo(
() => [styles.modalBackground, splashStyle],
[styles.modalBackground, splashStyle],
);
return React.useMemo(
() => (
<>
{animatedContent}
{buttons}
{siwePanel}
>
),
[backgroundStyle, styles.container, animatedContent, buttons, siwePanel],
);
}
const MemoizedLoggedOutModal: React.ComponentType =
React.memo(LoggedOutModal);
export default MemoizedLoggedOutModal;
diff --git a/native/account/registration/registration-types.js b/native/account/registration/registration-types.js
index 0c2c6e791..e35f1c490 100644
--- a/native/account/registration/registration-types.js
+++ b/native/account/registration/registration-types.js
@@ -1,71 +1,69 @@
// @flow
import type {
UpdateUserAvatarRequest,
ClientAvatar,
} from 'lib/types/avatar-types.js';
import type { NativeMediaSelection } from 'lib/types/media-types.js';
import type { SIWEResult, SIWEBackupSecrets } from 'lib/types/siwe-types.js';
export type CoolOrNerdMode = 'cool' | 'nerd';
export type EthereumAccountSelection = {
+accountType: 'ethereum',
...SIWEResult,
+avatarURI: ?string,
};
export type UsernameAccountSelection = {
+accountType: 'username',
+username: string,
+password: string,
};
export type AccountSelection =
| EthereumAccountSelection
| UsernameAccountSelection;
export type AvatarData =
| {
+needsUpload: true,
+mediaSelection: NativeMediaSelection,
+clientAvatar: ClientAvatar,
}
| {
+needsUpload: false,
+updateUserAvatarRequest: UpdateUserAvatarRequest,
+clientAvatar: ClientAvatar,
};
export type RegistrationServerCallInput = {
+coolOrNerdMode?: ?CoolOrNerdMode,
+keyserverURL?: ?string,
+farcasterID: ?string,
+accountSelection: AccountSelection,
+avatarData: ?AvatarData,
+siweBackupSecrets?: ?SIWEBackupSecrets,
+clearCachedSelections: () => void,
+onNonceExpired: () => mixed,
+onAlertAcknowledged?: () => mixed,
};
export type CachedUserSelections = {
+coolOrNerdMode?: CoolOrNerdMode,
+keyserverURL?: string,
+username?: string,
+password?: string,
+avatarData?: ?AvatarData,
+ethereumAccount?: ?EthereumAccountSelection,
+farcasterID?: string,
+siweBackupSecrets?: ?SIWEBackupSecrets,
};
export const ensAvatarSelection: AvatarData = {
needsUpload: false,
updateUserAvatarRequest: { type: 'ens' },
clientAvatar: { type: 'ens' },
};
-export const enableNewRegistrationMode = __DEV__;
-
export const enableSIWEBackupCreation = __DEV__;