Changeset View
Changeset View
Standalone View
Standalone View
native/account/siwe-panel.react.js
// @flow | // @flow | ||||
import BottomSheet from '@gorhom/bottom-sheet'; | import BottomSheet from '@gorhom/bottom-sheet'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { Alert } from 'react-native'; | import { Alert } from 'react-native'; | ||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'; | import { useSafeAreaInsets } from 'react-native-safe-area-context'; | ||||
import WebView from 'react-native-webview'; | import WebView from 'react-native-webview'; | ||||
import { | import { | ||||
getSIWENonce, | getSIWENonce, | ||||
getSIWENonceActionTypes, | getSIWENonceActionTypes, | ||||
siweAuth, | |||||
siweAuthActionTypes, | siweAuthActionTypes, | ||||
} from 'lib/actions/siwe-actions.js'; | } from 'lib/actions/siwe-actions.js'; | ||||
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; | import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; | ||||
import type { LogInStartingPayload } from 'lib/types/account-types.js'; | import type { SIWEWebViewMessage, SIWEResult } from 'lib/types/siwe-types.js'; | ||||
import type { SIWEWebViewMessage } from 'lib/types/siwe-types.js'; | |||||
import { | import { | ||||
useServerCall, | useServerCall, | ||||
useDispatchActionPromise, | useDispatchActionPromise, | ||||
} from 'lib/utils/action-utils.js'; | } from 'lib/utils/action-utils.js'; | ||||
import { commCoreModule } from '../native-modules.js'; | import { commCoreModule } from '../native-modules.js'; | ||||
import { NavContext } from '../navigation/navigation-context.js'; | |||||
import { useSelector } from '../redux/redux-utils.js'; | import { useSelector } from '../redux/redux-utils.js'; | ||||
import { nativeLogInExtraInfoSelector } from '../selectors/account-selectors.js'; | |||||
import { defaultLandingURLPrefix } from '../utils/url-utils.js'; | import { defaultLandingURLPrefix } from '../utils/url-utils.js'; | ||||
const commSIWE = `${defaultLandingURLPrefix}/siwe`; | const commSIWE = `${defaultLandingURLPrefix}/siwe`; | ||||
const getSIWENonceLoadingStatusSelector = createLoadingStatusSelector( | const getSIWENonceLoadingStatusSelector = createLoadingStatusSelector( | ||||
getSIWENonceActionTypes, | getSIWENonceActionTypes, | ||||
); | ); | ||||
const siweAuthLoadingStatusSelector = | const siweAuthLoadingStatusSelector = | ||||
createLoadingStatusSelector(siweAuthActionTypes); | createLoadingStatusSelector(siweAuthActionTypes); | ||||
type Props = { | type Props = { | ||||
+onClosed: () => mixed, | +onClosed: () => mixed, | ||||
+onClosing: () => mixed, | +onClosing: () => mixed, | ||||
+onSuccessfulWalletSignature: SIWEResult => mixed, | |||||
+closing: boolean, | +closing: boolean, | ||||
+setLoading: boolean => mixed, | +setLoading: boolean => mixed, | ||||
}; | }; | ||||
function SIWEPanel(props: Props): React.Node { | function SIWEPanel(props: Props): React.Node { | ||||
const navContext = React.useContext(NavContext); | |||||
const dispatchActionPromise = useDispatchActionPromise(); | const dispatchActionPromise = useDispatchActionPromise(); | ||||
const getSIWENonceCall = useServerCall(getSIWENonce); | const getSIWENonceCall = useServerCall(getSIWENonce); | ||||
const siweAuthCall = useServerCall(siweAuth); | |||||
const logInExtraInfo = useSelector(state => | |||||
nativeLogInExtraInfoSelector({ | |||||
redux: state, | |||||
navContext, | |||||
}), | |||||
); | |||||
const getSIWENonceCallFailed = useSelector( | const getSIWENonceCallFailed = useSelector( | ||||
state => getSIWENonceLoadingStatusSelector(state) === 'error', | state => getSIWENonceLoadingStatusSelector(state) === 'error', | ||||
); | ); | ||||
const { onClosing } = props; | const { onClosing } = props; | ||||
React.useEffect(() => { | React.useEffect(() => { | ||||
if (getSIWENonceCallFailed) { | if (getSIWENonceCallFailed) { | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | function SIWEPanel(props: Props): React.Node { | ||||
const bottomSheetRef = React.useRef(); | const bottomSheetRef = React.useRef(); | ||||
const snapToIndex = bottomSheetRef.current?.snapToIndex; | const snapToIndex = bottomSheetRef.current?.snapToIndex; | ||||
React.useEffect(() => { | React.useEffect(() => { | ||||
// When the snapPoints change, always reset to the first one | // When the snapPoints change, always reset to the first one | ||||
// Without this, when we close the WalletConnect modal we don't resize | // Without this, when we close the WalletConnect modal we don't resize | ||||
snapToIndex?.(0); | snapToIndex?.(0); | ||||
}, [snapToIndex, snapPoints]); | }, [snapToIndex, snapPoints]); | ||||
const callSIWE = React.useCallback( | |||||
async (message, signature, extraInfo) => { | |||||
try { | |||||
return await siweAuthCall({ | |||||
message, | |||||
signature, | |||||
...extraInfo, | |||||
}); | |||||
} catch (e) { | |||||
Alert.alert( | |||||
'Unknown error', | |||||
'Uhh... try again?', | |||||
[{ text: 'OK', onPress: onClosing }], | |||||
{ cancelable: false }, | |||||
); | |||||
throw e; | |||||
} | |||||
}, | |||||
[onClosing, siweAuthCall], | |||||
); | |||||
const handleSIWE = React.useCallback( | |||||
async ({ message, signature }) => { | |||||
const extraInfo = await logInExtraInfo(); | |||||
dispatchActionPromise( | |||||
siweAuthActionTypes, | |||||
callSIWE(message, signature, extraInfo), | |||||
undefined, | |||||
({ calendarQuery: extraInfo.calendarQuery }: LogInStartingPayload), | |||||
); | |||||
}, | |||||
[logInExtraInfo, dispatchActionPromise, callSIWE], | |||||
); | |||||
const closeBottomSheet = bottomSheetRef.current?.close; | const closeBottomSheet = bottomSheetRef.current?.close; | ||||
const { closing } = props; | const { closing, onSuccessfulWalletSignature } = props; | ||||
const disableOnClose = React.useRef(false); | const disableOnClose = React.useRef(false); | ||||
const handleMessage = React.useCallback( | const handleMessage = React.useCallback( | ||||
async event => { | async event => { | ||||
const data: SIWEWebViewMessage = JSON.parse(event.nativeEvent.data); | const data: SIWEWebViewMessage = JSON.parse(event.nativeEvent.data); | ||||
if (data.type === 'siwe_success') { | if (data.type === 'siwe_success') { | ||||
const { address, message, signature } = data; | const { address, message, signature } = data; | ||||
if (address && signature) { | if (address && signature) { | ||||
disableOnClose.current = true; | disableOnClose.current = true; | ||||
closeBottomSheet?.(); | closeBottomSheet?.(); | ||||
await handleSIWE({ message, signature }); | await onSuccessfulWalletSignature({ address, message, signature }); | ||||
} | } | ||||
} else if (data.type === 'siwe_closed') { | } else if (data.type === 'siwe_closed') { | ||||
onClosing(); | onClosing(); | ||||
closeBottomSheet?.(); | closeBottomSheet?.(); | ||||
} else if (data.type === 'walletconnect_modal_update') { | } else if (data.type === 'walletconnect_modal_update') { | ||||
setWalletConnectModalOpen(data.state === 'open'); | setWalletConnectModalOpen(data.state === 'open'); | ||||
} | } | ||||
}, | }, | ||||
[handleSIWE, onClosing, closeBottomSheet], | [onSuccessfulWalletSignature, onClosing, closeBottomSheet], | ||||
); | ); | ||||
const prevClosingRef = React.useRef(); | const prevClosingRef = React.useRef(); | ||||
React.useEffect(() => { | React.useEffect(() => { | ||||
if (closing && !prevClosingRef.current) { | if (closing && !prevClosingRef.current) { | ||||
closeBottomSheet?.(); | closeBottomSheet?.(); | ||||
} | } | ||||
prevClosingRef.current = closing; | prevClosingRef.current = closing; | ||||
}, [closing, closeBottomSheet]); | }, [closing, closeBottomSheet]); | ||||
▲ Show 20 Lines • Show All 76 Lines • Show Last 20 Lines |