diff --git a/landing/connect-farcaster.react.js b/landing/connect-farcaster.react.js --- a/landing/connect-farcaster.react.js +++ b/landing/connect-farcaster.react.js @@ -3,15 +3,7 @@ import { AuthKitProvider, useSignIn } from '@farcaster/auth-kit'; import * as React from 'react'; -type FarcasterWebViewMessage = - | { - +type: 'farcaster_url', - +url: string, - } - | { - +type: 'farcaster_data', - +fid: string, - }; +import type { FarcasterWebViewMessage } from 'lib/types/farcaster-types.js'; const config = { domain: 'Comm', diff --git a/lib/types/farcaster-types.js b/lib/types/farcaster-types.js new file mode 100644 --- /dev/null +++ b/lib/types/farcaster-types.js @@ -0,0 +1,15 @@ +// @flow + +// This is a message that the rendered webpage +// (landing/connect-farcaster.react.js) uses to communicate back +// to the React Native WebView that is rendering it +// (native/components/farcaster-web-view.react.js) +export type FarcasterWebViewMessage = + | { + +type: 'farcaster_url', + +url: string, + } + | { + +type: 'farcaster_data', + +fid: string, + }; diff --git a/native/account/siwe-panel.react.js b/native/account/siwe-panel.react.js --- a/native/account/siwe-panel.react.js +++ b/native/account/siwe-panel.react.js @@ -25,6 +25,7 @@ import { useKeyboardHeight } from '../keyboard/keyboard-hooks.js'; import { useSelector } from '../redux/redux-utils.js'; import type { BottomSheetRef } from '../types/bottom-sheet.js'; +import type { WebViewMessageEvent } from '../types/web-view-types.js'; import { UnknownErrorAlertDetails } from '../utils/alert-messages.js'; import Alert from '../utils/alert.js'; import { defaultLandingURLPrefix } from '../utils/url-utils.js'; @@ -40,14 +41,6 @@ const legacySiweAuthLoadingStatusSelector = createLoadingStatusSelector(siweAuthActionTypes); -type WebViewMessageEvent = { - +nativeEvent: { - +data: string, - ... - }, - ... -}; - type Props = { +onClosed: () => mixed, +onClosing: () => mixed, diff --git a/native/components/farcaster-web-view.react.js b/native/components/farcaster-web-view.react.js new file mode 100644 --- /dev/null +++ b/native/components/farcaster-web-view.react.js @@ -0,0 +1,71 @@ +// @flow + +import * as React from 'react'; +import { View, Linking } from 'react-native'; +import WebView from 'react-native-webview'; + +import type { FarcasterWebViewMessage } from 'lib/types/farcaster-types.js'; + +import type { WebViewMessageEvent } from '../types/web-view-types.js'; +import { defaultLandingURLPrefix } from '../utils/url-utils.js'; + +const commConnectFarcasterURL = `${defaultLandingURLPrefix}/connect-farcaster`; + +const webViewSource = { uri: commConnectFarcasterURL }; + +const webViewOriginWhitelist = ['*']; + +export type FarcasterWebViewState = 'closed' | 'opening'; + +type Props = { + +onSuccess: (fid: string) => mixed, + +webViewState: FarcasterWebViewState, +}; + +function FarcasterWebView(props: Props): React.Node { + const { onSuccess, webViewState } = props; + + const handleMessage = React.useCallback( + (event: WebViewMessageEvent) => { + const data: FarcasterWebViewMessage = JSON.parse(event.nativeEvent.data); + + if (data.type === 'farcaster_url') { + void Linking.openURL(data.url); + } else if (data.type === 'farcaster_data') { + onSuccess(data.fid); + } + }, + [onSuccess], + ); + + const webView = React.useMemo(() => { + if (webViewState === 'closed') { + return null; + } + + return ( + + + + ); + }, [handleMessage, webViewState]); + + return webView; +} + +const styles = { + webViewContainer: { + height: 0, + overflow: 'hidden', + }, + connectButtonContainer: { + marginHorizontal: 16, + }, +}; + +export default FarcasterWebView; diff --git a/native/types/web-view-types.js b/native/types/web-view-types.js new file mode 100644 --- /dev/null +++ b/native/types/web-view-types.js @@ -0,0 +1,9 @@ +// @flow + +export type WebViewMessageEvent = { + +nativeEvent: { + +data: string, + ... + }, + ... +};