Skip to content

Instantly share code, notes, and snippets.

@vasylnahuliak
Created January 24, 2025 15:53
Show Gist options
  • Save vasylnahuliak/c1ec59698aadf06c258df52bbc92d1f8 to your computer and use it in GitHub Desktop.
Save vasylnahuliak/c1ec59698aadf06c258df52bbc92d1f8 to your computer and use it in GitHub Desktop.
Example of using usePromiseRef with WebView onMessage
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