diff --git a/native/account/qr-auth/connect-secondary-device.react.js b/native/account/qr-auth/connect-secondary-device.react.js new file mode 100644 --- /dev/null +++ b/native/account/qr-auth/connect-secondary-device.react.js @@ -0,0 +1,73 @@ +// @flow + +import invariant from 'invariant'; +import * as React from 'react'; +import { Text } from 'react-native'; + +import { QRAuthContext } from './qr-auth-context.js'; +import type { QRAuthNavigationProp } from './qr-auth-navigator.react.js'; +import RegistrationButtonContainer from '../../account/registration/registration-button-container.react.js'; +import RegistrationContainer from '../../account/registration/registration-container.react.js'; +import RegistrationContentContainer from '../../account/registration/registration-content-container.react.js'; +import PrimaryButton from '../../components/primary-button.react.js'; +import { type NavigationRoute } from '../../navigation/route-names.js'; +import { useStyles } from '../../themes/colors.js'; + +export type ConnectSecondaryDeviceParams = { + +data: string, +}; + +type Props = { + +navigation: QRAuthNavigationProp<'ConnectSecondaryDevice'>, + +route: NavigationRoute<'ConnectSecondaryDevice'>, +}; + +function ConnectSecondaryDevice(props: Props): React.Node { + const { route } = props; + const data = route.params?.data; + + const styles = useStyles(unboundStyles); + + const qrAuthContext = React.useContext(QRAuthContext); + invariant(qrAuthContext, 'qrAuthContext should be set'); + const { onConnect, connectingInProgress } = qrAuthContext; + + const onPressConnect = React.useCallback(() => { + void onConnect(data); + }, [data, onConnect]); + + return ( + + + Connect with this device? + + Are you sure you want to allow this device to log in to your account? + + + + + + + ); +} + +const unboundStyles = { + header: { + fontSize: 24, + color: 'panelForegroundLabel', + paddingBottom: 16, + }, + body: { + fontFamily: 'Arial', + fontSize: 15, + lineHeight: 20, + color: 'panelForegroundSecondaryLabel', + paddingBottom: 16, + }, +}; + +export default ConnectSecondaryDevice; diff --git a/native/account/qr-auth/qr-auth-context-provider.js b/native/account/qr-auth/qr-auth-context-provider.js --- a/native/account/qr-auth/qr-auth-context-provider.js +++ b/native/account/qr-auth/qr-auth-context-provider.js @@ -43,6 +43,7 @@ const aes256Key = React.useRef(null); const secondaryDeviceID = React.useRef(null); const secondaryDeviceType = React.useRef(null); + const [connectingInProgress, setConnectingInProgress] = React.useState(false); const ownPeerDevices = useSelector(getOwnPeerDevices); const keyserverDeviceID = getKeyserverDeviceID(ownPeerDevices); @@ -90,6 +91,8 @@ return; } + setConnectingInProgress(false); + Alert.alert('Device added', 'Device registered successfully', [ { text: 'OK', onPress: goBack }, ]); @@ -189,6 +192,7 @@ ], ); } catch (err) { + setConnectingInProgress(false); console.log('Primary device error:', err); Alert.alert('Adding device failed', 'Failed to update the device list', [ { text: 'OK' }, @@ -205,6 +209,8 @@ const onConnect = React.useCallback( async (data: string) => { + setConnectingInProgress(true); + const parsedData = parseDataFromDeepLink(data); const keysMatch = parsedData?.data?.keys; @@ -214,6 +220,7 @@ 'QR code does not contain a valid pair of keys.', [{ text: 'OK' }], ); + setConnectingInProgress(false); return; } @@ -224,6 +231,7 @@ secondaryDeviceID.current = ed25519; secondaryDeviceType.current = parsedData.data.deviceType; } catch (err) { + setConnectingInProgress(false); console.log('Failed to decode URI component:', err); return; } @@ -236,8 +244,9 @@ const contextValue = React.useMemo( () => ({ onConnect, + connectingInProgress, }), - [onConnect], + [onConnect, connectingInProgress], ); return ( diff --git a/native/account/qr-auth/qr-auth-context.js b/native/account/qr-auth/qr-auth-context.js --- a/native/account/qr-auth/qr-auth-context.js +++ b/native/account/qr-auth/qr-auth-context.js @@ -4,6 +4,7 @@ export type QRAuthContextType = { +onConnect: (data: string) => Promise, + +connectingInProgress: boolean, }; const QRAuthContext: React.Context = diff --git a/native/account/qr-auth/qr-auth-navigator.react.js b/native/account/qr-auth/qr-auth-navigator.react.js --- a/native/account/qr-auth/qr-auth-navigator.react.js +++ b/native/account/qr-auth/qr-auth-navigator.react.js @@ -7,11 +7,13 @@ import { createStackNavigator } from '@react-navigation/stack'; import * as React from 'react'; +import ConnectSecondaryDevice from './connect-secondary-device.react.js'; import { QRAuthContextProvider } from './qr-auth-context-provider.js'; import QRAuthNotPrimaryDevice from './qr-auth-not-primary-device.react.js'; import SecondaryDeviceQRCodeScanner from './secondary-device-qr-code-scanner.react.js'; import type { RootNavigationProp } from '../../navigation/root-navigator.react.js'; import { + ConnectSecondaryDeviceRouteName, type NavigationRoute, type QRAuthNavigatorParamList, QRAuthNotPrimaryDeviceRouteName, @@ -64,6 +66,10 @@ name={QRAuthNotPrimaryDeviceRouteName} component={QRAuthNotPrimaryDevice} /> + ); diff --git a/native/navigation/route-names.js b/native/navigation/route-names.js --- a/native/navigation/route-names.js +++ b/native/navigation/route-names.js @@ -4,6 +4,7 @@ import type { ActionResultModalParams } from './action-result-modal.react.js'; import type { InviteLinkModalParams } from './invite-link-modal.react'; +import type { ConnectSecondaryDeviceParams } from '../account/qr-auth/connect-secondary-device.react.js'; import type { AvatarSelectionParams } from '../account/registration/avatar-selection.react.js'; import type { ConnectEthereumParams } from '../account/registration/connect-ethereum.react.js'; import type { ConnectFarcasterParams } from '../account/registration/connect-farcaster.react.js'; @@ -181,6 +182,7 @@ export const NUXTipOverlayBackdropRouteName = 'NUXTipOverlayBackdrop'; export const QRAuthNavigatorRouteName = 'QRAuthNavigator'; export const QRAuthNotPrimaryDeviceRouteName = 'QRAuthNotPrimaryDevice'; +export const ConnectSecondaryDeviceRouteName = 'ConnectSecondaryDevice'; export type RootParamList = { +LoggedOutModal: void, @@ -356,6 +358,7 @@ export type QRAuthNavigatorParamList = { +SecondaryDeviceQRCodeScanner: void, +QRAuthNotPrimaryDevice: void, + +ConnectSecondaryDevice: ConnectSecondaryDeviceParams, }; export type ScreenParamList = {