From 447f979904ba31279728e743680d5a561a926c87 Mon Sep 17 00:00:00 2001 From: Luis Marsiglia Date: Mon, 21 Nov 2022 17:16:50 -0400 Subject: [PATCH] feat: add `autoResetOnExpire` prop --- README.md | 42 +++++++++++++++++++----- packages/example/src/components/Demo.tsx | 8 ++++- src/lib.tsx | 23 ++++++++++--- src/types.d.ts | 9 +++-- 4 files changed, 65 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index eb3f3a1..3539e76 100644 --- a/README.md +++ b/README.md @@ -58,14 +58,15 @@ function Widget() { ## Props -| **Prop** | **Type** | **Description** | **Required** | -| ----------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | -| siteKey | `string` | Your sitekey key, get one from [here](https://developers.cloudflare.com/turnstile/get-started/). | ✅ | -| options | `object` | Widget render options. More info about this options [below](https://github.com/marsidev/react-turnstile/#render-options). | | -| scriptProps | `object` | You can customize the injected `script` tag with this prop. It allows you to add `async`, `defer`, `nonce` attributes to the script tag. You can also control whether the injected script will be added to the document body or head with `appendTo` attribute. | | -| onSuccess | `function` | Callback that is invoked upon success of the challenge. The callback is passed a token that can be validated. | | -| onExpire | `function` | Callback that is invoked when a challenge expires. | | -| onError | `function` | Callback that is invoked when there is a network error. | | +| **Prop** | **Type** | **Description** | **Required** | +| ----------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | +| siteKey | `string` | Your sitekey key, get one from [here](https://developers.cloudflare.com/turnstile/get-started/). | ✅ | +| options | `object` | Widget render options. More info about this options [below](https://github.com/marsidev/react-turnstile/#render-options). | | +| scriptProps | `object` | You can customize the injected `script` tag with this prop. It allows you to add `async`, `defer`, `nonce` attributes to the script tag. You can also control whether the injected script will be added to the document body or head with `appendTo` attribute. | | +| onSuccess | `function` | Callback that is invoked upon success of the challenge. The callback is passed a token that can be validated. | | +| onExpire | `function` | Callback that is invoked when a challenge expires. | | +| onError | `function` | Callback that is invoked when there is a network error. | | +| autoResetOnExpire | `boolean` | Controls whether the widget should automatically reset when it expires. If is set to `true`, you don't need to use the `onExpire` callback. Default to `true`. | | ### Render options @@ -148,6 +149,8 @@ function Widget() { } ``` +> `onExpire` does not take effect unless you set `autoResetOnExpire` to `false`. + ### Getting the token after solving the challenge: ```jsx import { useState } from 'react' @@ -220,7 +223,7 @@ function Widget() { ### Validating a token: ```jsx // LoginForm.jsx -import { useRef, useState } from 'react' +import { useRef } from 'react' import { Turnstile } from '@marsidev/react-turnstile' export default function LoginForm() { @@ -288,6 +291,27 @@ export default async function handler(request, response) { > - by calling the `.getResponse()` method. > - by reading the widget response input with name `cf-turnstile-response`. This one is not an option if you set `options.fieldResponse` to `false`. +### Handling widget expiring: + +> By default, you don't need to handle the widget expiring, unless you set `autoResetOnExpire` to `false`. + +```jsx +import { useRef } from 'react' +import { Turnstile } from '@marsidev/react-turnstile' + +function Widget() { + const ref = useRef(null) + + return ( + ref.current?.reset()} + /> + ) +} +``` ## Contributing diff --git a/packages/example/src/components/Demo.tsx b/packages/example/src/components/Demo.tsx index cfd8bf0..fe06c38 100644 --- a/packages/example/src/components/Demo.tsx +++ b/packages/example/src/components/Demo.tsx @@ -56,6 +56,11 @@ const Demo = () => { setStatus('solved') } + const onExpire = () => { + setStatus('expired') + turnstileRef.current?.reset() + } + return (
@@ -63,10 +68,11 @@ const Demo = () => { setStatus('error')} - onExpire={() => setStatus('expired')} + onExpire={onExpire} onSuccess={onSuccess} /> diff --git a/src/lib.tsx b/src/lib.tsx index af11033..3e94a4a 100644 --- a/src/lib.tsx +++ b/src/lib.tsx @@ -3,7 +3,17 @@ import { DEFAULT_CONTAINER_ID, DEFAULT_ONLOAD_NAME, injectTurnstileScript } from import { RenderParameters, TurnstileInstance, TurnstileProps } from './types' export const Turnstile = forwardRef((props, ref) => { - const { scriptOptions, options, siteKey, onSuccess, onExpire, onError, id, ...divProps } = props + const { + scriptOptions, + options, + siteKey, + onSuccess, + onExpire, + onError, + id, + autoResetOnExpire = true, + ...divProps + } = props const config = options ?? {} const [widgetId, setWidgetId] = useState() @@ -119,11 +129,13 @@ export const Turnstile = forwardRef window.turnstile?.reset(), 250 * 250) + if (autoResetOnExpire) { + // expire time it's documented as 300 seconds but can happen in around 290 seconds. + const timerId = setInterval(() => window.turnstile?.reset(), 290 * 1000) - return () => { - clearInterval(timerId) + return () => { + clearInterval(timerId) + } } }, [configJson, scriptOptionsJson]) @@ -144,4 +156,5 @@ export const Turnstile = forwardRef` component */ -interface ComponentOptions extends TurnstileBaseOptions { +interface ComponentRenderOptions extends TurnstileBaseOptions { /** * The tabindex of Turnstile’s iframe for accessibility purposes. * @default 0 @@ -194,11 +194,16 @@ interface TurnstileProps extends React.HTMLAttributes { /** * Custom widget render options. See {@link https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/#configurations the docs} for more info about this options. */ - options?: ComponentOptions + options?: ComponentRenderOptions /** * Custom injected script options. */ scriptOptions?: ScriptOptions + /** + * Controls whether the widget should automatically reset when it expires. + * @default true + */ + autoResetOnExpire?: boolean } interface InjectTurnstileScriptParams {