Created
January 24, 2025 15:53
-
-
Save vasylnahuliak/c1ec59698aadf06c258df52bbc92d1f8 to your computer and use it in GitHub Desktop.
Example of using usePromiseRef with WebView onMessage
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { FC, useImperativeHandle, useRef } from 'react'; | |
import { Text, View, TouchableOpacity } from "react-native"; | |
import ConfirmHcaptcha from '@hcaptcha/react-native-hcaptcha'; | |
import type { WebViewMessageEvent } from 'react-native-webview'; | |
import { isFunction, isString } from 'lodash'; | |
import { usePromiseRef } from './usePromiseRef'; | |
HCaptchaImperativeRefValue = { | |
getToken: () => Promise<string>; | |
}; | |
type HCaptchaProps = { | |
HCaptchaImperativeRef: React.MutableRefObject<HCaptchaImperativeRefValue>; | |
}; | |
export const useHCaptchaImperativeRef = () => { | |
const HCaptchaImperativeRef = useRef<HCaptchaImperativeRefValue>({ | |
getToken: async () => { | |
return Promise.reject(HCaptchaStatus.InitialRef); | |
}, | |
}); | |
return { | |
HCaptchaImperativeRef, | |
}; | |
}; | |
export const HCaptchaStatus = { | |
Cancel: 'cancel', | |
Error: 'error', | |
Expired: 'expired', | |
InitialRef: 'initialRef', | |
PromiseNotCreated: 'promiseNotCreated', | |
} as const; | |
export const HCaptcha: FC<HCaptchaProps> = ({ HCaptchaImperativeRef }) => { | |
const [promiseRef, createPromise] = usePromiseRef<string, string>(); | |
const hcaptchaRef = useRef<ConfirmHcaptcha>(null); | |
useImperativeHandle(HCaptchaImperativeRef, () => ({ | |
getToken: (): Promise<string> => { | |
createPromise(); | |
if (!promiseRef.current) { | |
return Promise.reject(HCaptchaStatus.PromiseNotCreated); | |
} | |
hcaptchaRef.current?.show(); | |
return promiseRef.current.promise; | |
}, | |
})); | |
const handleMessage = (event: WebViewMessageEvent) => { | |
if (event?.nativeEvent?.data && isString(event.nativeEvent.data)) { | |
switch (event.nativeEvent.data) { | |
case 'cancel': | |
hcaptchaRef.current?.hide(); | |
promiseRef.current?.reject(HCaptchaStatus.Cancel); | |
break; | |
case 'error': | |
hcaptchaRef.current?.hide(); | |
promiseRef.current?.reject(HCaptchaStatus.Error); | |
break; | |
case 'expired': | |
hcaptchaRef.current?.hide(); | |
promiseRef.current?.reject(HCaptchaStatus.Expired); | |
break; | |
case 'open': | |
// NOTE: should not do anything here | |
// do not remove this case because the default case will be triggered | |
break; | |
default: | |
hcaptchaRef.current?.hide(); | |
// NOTE: the library does not have "markUsed" method in types | |
if ('markUsed' in event && isFunction(event.markUsed)) { | |
event.markUsed(); | |
} | |
promiseRef.current?.resolve(event.nativeEvent.data); | |
break; | |
} | |
} | |
}; | |
return ( | |
<ConfirmHcaptcha | |
ref={hcaptchaRef} | |
siteKey={HCAPTCHA_SITE_KEY} | |
onMessage={handleMessage} | |
size="invisible" | |
hasBackdrop={false} | |
showLoading={false} | |
closableLoading={true} | |
/> | |
); | |
}; | |
export const Example = () => { | |
const { HCaptchaImperativeRef } = useHCaptchaImperativeRef(); | |
const handlePress = async () => { | |
try { | |
const token = await HCaptchaImperativeRef.current?.getToken(); | |
// TODO: pass token to your backend | |
Alert.alert('Token', token); | |
} catch (error) { | |
Alert.alert('Error', error); | |
} | |
} | |
return ( | |
<View> | |
<TouchableOpacity onPress={handlePress}> | |
<Text>Button</Text> | |
</TouchableOpacity> | |
<HCaptcha HCaptchaImperativeRef={HCaptchaImperativeRef} /> | |
<View/> | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment